home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / memory / ems40v11.zip / EMS40.ASM next >
Assembly Source File  |  1989-07-19  |  80KB  |  2,201 lines

  1. ;============================================================================
  2. ;EMS40.SYS an Expanded Memory Simulator for the IBM AT
  3. ;
  4. ; Revision History:
  5. ;
  6. ;   Version 1.0         Initial Release              PC Mag Vol 8, Num 12
  7. ;
  8. ;   Version 1.1         Enlarged internal save       July 18, 1989
  9. ;                       area for functions 8 & 9.
  10. ;
  11. ;                       Reduced default number of
  12. ;                       possible from 255 to 127.
  13. ;
  14. ;                       Bug fixes:
  15. ;                        Fun 23. Preserve CX on call.
  16. ;                        Fun 2500. Return size in CX.
  17. ;
  18. ;============================================================================
  19.         PAGE    ,132
  20. CODE        SEGMENT PUBLIC'code'
  21.         ASSUME    CS:CODE
  22. ;-----------------------------------------------------------------------------
  23. ;Structure of the device driver request header
  24. ;-----------------------------------------------------------------------------
  25. REQ_STRUC    STRUC
  26. LEN        DB    ?
  27. UNIT        DB    ?            ;unit number
  28. COMMAND        DB    ?            ;command code
  29. STATUS        DW    ?            ;return status
  30. RESERVE        DB    8 DUP (?)
  31. MEDIA        DB    ?
  32. ADDRESS        DD    ?            ;Transfer address
  33. CONFIG_PTR    DD    ?            ;Pointer to line in config
  34. REQ_STRUC    ENDS
  35. ;-----------------------------------------------------------------------------
  36. ;Segment descriptor structure
  37. ;-----------------------------------------------------------------------------
  38. DAT_SEG_DES    STRUC                ;data segment descriptor
  39. SEG_LIM        DW    0            ;length of segment
  40. BASE_ADRL    DW    0            ;base address of segment
  41. BASE_ADRH    DB    0
  42.         DB    0            ;access rights byte
  43.         DW    0            ;reserved
  44. DAT_SEG_DES    ENDS
  45. ;=============================================================================
  46. ;Device header begin
  47. ;=============================================================================
  48.         ORG    0            ;drivers start at offset 0
  49. HEADER        DD    -1                      ;Pointer to next driver
  50.         DW    8000H            ;device attribute word
  51.         DW    OFFSET STRATEGY        ;pointer to strategy routine
  52.         DW    OFFSET INTERRUPT        ;pointer to interrupt routine
  53.         DB    'EMMXXXX0'        ;name of driver
  54. ;Device header end
  55. SWAP_POINTER    DW    OFFSET EMS_EXCH_PAG
  56. PROGRAM        DB    "EMS 4.0 Simulator, Ver. 1.1"
  57. COPYRIGHT    DB    " (C) 1989 Ziff Communications",13,10
  58. PROGRAMMER    DB    "PC Magazine ",254," Douglas Boling",13,10,"$",26
  59. REQ_HEADADR    DD    ?            ;Far pointer to request header
  60. ;-----------------------------------------------------------------------------
  61. ;Global Descriptor table needed for moves to and from extended memory.
  62. ;-----------------------------------------------------------------------------
  63. GDT        LABEL    BYTE
  64.         DAT_SEG_DES <>            ;Dummy
  65.         DAT_SEG_DES <>            ;GDT descriptor
  66. SOURCE        DAT_SEG_DES <4000H,,,93H,>    ;source descriptor
  67. DEST        DAT_SEG_DES <4000H,,,93H,>    ;destination descriptor
  68.         DAT_SEG_DES <>            ;bios code descriptor
  69.         DAT_SEG_DES <>            ;stack segment descriptor
  70. ;=============================================================================
  71. ;Strategy routine. This routine stores the address of the request header
  72. ;=============================================================================
  73. STRATEGY    PROC    FAR
  74.         ASSUME  CS:CODE,DS:NOTHING,ES:NOTHING
  75.         MOV    WORD PTR CS:[REQ_HEADADR],BX    ;save offset
  76.         MOV    WORD PTR CS:[REQ_HEADADR+2],ES    ;save segment
  77.         RET
  78. STRATEGY    ENDP
  79. ;=============================================================================
  80. ;Interrupt routine. This routine executes the command code in the req header.
  81. ;=============================================================================
  82. INTERRUPT    PROC    FAR
  83.         ASSUME  CS:CODE,DS:NOTHING,ES:NOTHING
  84.         PUSHF
  85.         PUSH    AX            ;save every register used
  86.         PUSH    BX
  87.         PUSH    CX
  88.         PUSH    DX
  89.         PUSH    DI
  90.         PUSH    SI
  91.         PUSH    DS
  92.         PUSH    ES
  93.         PUSH    CS            ;Set DS
  94.         POP    DS
  95.         ASSUME  DS:CODE
  96.         CLD                ;any string operations move up.
  97. ;Get command from request header
  98.         LES    DI,[REQ_HEADADR]    ;load address of req header
  99.         ASSUME    ES:NOTHING
  100.         MOV    BL,ES:[DI.COMMAND]
  101.         CMP    BL,0
  102.         JNE    PROCESS1
  103.         CALL    INITIALIZE
  104.         JMP    SHORT DONE
  105. PROCESS1:    CMP    BL,16            ;see if command out of range
  106.         JBE    DONE
  107.         MOV    AX,8003H        ;unknown command error code
  108. DONE:        OR    AX,0100H        ;set the 'done' bit
  109.         MOV    ES:[DI.STATUS],AX
  110.         POP    ES            ;restore registers before exit
  111.         POP    DS
  112.         POP    SI
  113.         POP    DI
  114.         POP    DX
  115.         POP    CX
  116.         POP    BX
  117.         POP    AX
  118.         POPF
  119.         RET
  120. INTERRUPT    ENDP
  121. DRIVER_END    =    $            ;Last part of driver code
  122. ;======================================================================
  123. ;EMS Driver code starts here.
  124. ;======================================================================
  125. OLD_INT15H    LABEL DWORD
  126. OLD_INT15HO    DW    ?            ;offset of old interrupt vector
  127. OLD_INT15HS    DW    ?            ;segment
  128. EXT_MEM_LIMIT    DW    0            ;adjusted top of avail memory
  129. OS_ENABLED    DB    1            ;Enable os functions 1=enabled
  130. OS_PASS_LOW    DW    0            ;Operating system password.
  131. OS_PASS_HIGH     DW    0
  132. ALT_MAP_PTRS     DW    0            ;Mapping pointer for funct 28
  133. ALT_MAP_PTRO     DW    0
  134. WINDOW_SEG    DW    ?            ;starting segment of ems win
  135. WINDOW_ADDR_BASE    DD    4 DUP(0)    ;address of each page
  136. EXTEND_ADRL    DW    ?            ;base of extended memory used
  137. EXTEND_ADRH    DB    ?
  138. TOTAL_PAGES    DW    24            ;default to 384k of exp mem.
  139. TOTAL_HANDLES    DW    127            ;Default number of handles
  140. INT_SAVE_SIZE    DW    15            ;Number of save areas for 8/9
  141. PAG_OWNER_TBL    DW    ?            ;Pointer to page table
  142. HANDLE_ARRAY     DW    ?                       ;Pointer to handle table
  143. MAP_ARRAY_PTR     DW    ?                       ;Pointer to map array
  144. MOVE_BUSY_FLAG    DB    0            ;Indicates blk move active
  145. SAVED_ADDR_LOW    DW    0            ;Saved address of block
  146. SAVED_ADDR_HIGH    DB    0            ;  being moved.
  147. ;======================================================================
  148. ;Interrupt 15h routine. Intercept extended memory size determine.
  149. ;======================================================================
  150. INT_15H        PROC    FAR
  151.         ASSUME  CS:CODE,DS:NOTHING,ES:NOTHING
  152.         CMP    AH,88H
  153.         JE    INT15_F88
  154.         JMP    CS:[OLD_INT15H]
  155. INT15_F88:    MOV    AX,CS:EXT_MEM_LIMIT             ;provide new limit
  156.         CLC                                     ;clear error flag
  157.         RET    2
  158. INT_15H        ENDP
  159. ;-----------------------------------------------------------------------------
  160. ;Jump table for EMS driver commands
  161. ;-----------------------------------------------------------------------------
  162. EMS_CMDS    DW    OFFSET EMS_01        ;Get status
  163.         DW    OFFSET EMS_02        ;Get page frame seg address
  164.         DW    OFFSET EMS_03        ;Get unallocated page count
  165.         DW    OFFSET EMS_04        ;Allocate pages
  166.         DW    OFFSET EMS_05        ;Map/unmap handle pages
  167.         DW    OFFSET EMS_06        ;Deallocate pages
  168.         DW    OFFSET EMS_07        ;Get version
  169.         DW    OFFSET EMS_08        ;Save page map
  170.         DW    OFFSET EMS_09        ;Restore page map
  171.         DW    OFFSET EMS_UNSP        ;reserved
  172.         DW    OFFSET EMS_UNSP        ;reserved
  173.         DW    OFFSET EMS_12        ;Get handle count
  174.         DW    OFFSET EMS_13        ;Get handle pages
  175.         DW    OFFSET EMS_14        ;Get all handle pages
  176.         DW    OFFSET EMS_15        ;Page map functions
  177.         DW    OFFSET EMS_16        ;Partial page map functions
  178.         DW    OFFSET EMS_17        ;Map/unmap multiple hndl pages
  179.         DW    OFFSET EMS_18        ;Reallocate pages
  180.         DW    OFFSET EMS_19        ;Handle attribute
  181.         DW    OFFSET EMS_20        ;Handle name
  182.         DW    OFFSET EMS_21        ;Handle directory
  183.         DW    OFFSET EMS_22        ;Alter page map and jump
  184.         DW    OFFSET EMS_23        ;Alter page map and call
  185.         DW    OFFSET EMS_24        ;move/exchange memory region
  186.         DW    OFFSET EMS_25        ;Get mappable phys addr array
  187.         DW    OFFSET EMS_26        ;Hardware configuration
  188.         DW    OFFSET EMS_27        ;Allocate standard pages
  189.         DW    OFFSET EMS_28        ;Alternate map register set
  190.         DW    OFFSET EMS_UNSP        ;Warmboot preparation
  191.         DW    OFFSET EMS_30        ;OS/E functions
  192. ;======================================================================
  193. ;Interrupt 67h routine. EMS driver function dispatcher.
  194. ;======================================================================
  195. INT_67H        PROC    FAR
  196.         ASSUME     CS:CODE,DS:NOTHING,ES:NOTHING
  197.         PUSH    BP
  198.         MOV    BP,SP            ;set up stack addressing
  199.         CLD                ;any string operations move up.
  200.         PUSH    CX            ;Save registers
  201.         PUSH    DI            ;NOTE: Don't change the
  202.         PUSH    SI                      ;  order of the register save.
  203.         PUSH    DS                      ;  Many of the routines depend
  204.         PUSH    ES                      ;  on the correct order.
  205.         PUSH    CS            ;point ds to code segment
  206.         POP    DS
  207.         ASSUME  DS:CODE
  208.         CMP    AH,5DH            ;Check for a cmd out of range
  209.         JA    EMS_CMD_ERR
  210.         CMP    AH,40H
  211.         JL    EMS_CMD_ERR
  212.         MOV    DI,OFFSET RETURN_ADDR    ;Push return address onto
  213.         PUSH    DI            ;  stack.
  214.         PUSH    AX            ;save AX
  215.         SUB    AH,40H            ;Convert command code in AX
  216.         MOV    AL,AH            ;  into a jump address.
  217.         XOR    AH,AH                   ;Clear upper byte
  218.         SAL    AX,1            ;Convert to word offset
  219.         ADD    AX,OFFSET EMS_CMDS    ;add offset of jump table
  220.         MOV    DI,AX            ;Copy to DI
  221.         POP    AX            ;restore AX
  222.         PUSH    [DI]            ;Put offset of routine on stk
  223.         MOV    DI,[BP-4]        ;Restore DI
  224.         CALL    EMS_CHECK_HDL           ;check for valid handle in DX
  225.         DB    0C3h            ;RETN opcode to call function.
  226. RETURN_ADDR:    POP    ES            ;  The RETN instruction is
  227.         POP    DS            ;  hand assembled to force a
  228.         POP    SI                      ;  near return in a far proc.
  229.         POP    DI            ;  For MASM 5.0, the RETN can
  230.         POP    CX            ;  be specified as an opcode.
  231.         POP    BP
  232.         IRET
  233. EMS_CMD_ERR:    MOV    AH,84H                  ;EMS command out of range
  234.         JMP    SHORT RETURN_ADDR
  235. INT_67H        ENDP
  236. ;======================================================================
  237. ;Function 1.  Get status.
  238. ;======================================================================
  239. EMS_01        PROC    NEAR
  240.         ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  241.         XOR    AX,AX
  242.         RET
  243. EMS_01        ENDP
  244. ;======================================================================
  245. ;Function 2.  Get segment address of EMS window
  246. ;======================================================================
  247. EMS_02        PROC    NEAR
  248.         ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  249.         MOV    BX,WINDOW_SEG        ;store starting seg of window
  250.         XOR    AX,AX
  251.         RET
  252. EMS_02        ENDP
  253. ;======================================================================
  254. ;Function 3.  Get count of unallocated pages
  255. ;======================================================================
  256. EMS_03        PROC    NEAR
  257.         ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  258.         XOR    DX,DX            ;search for hndl =-1 (unaloc)
  259.         DEC    DX
  260.         CLC                ;fake 'handle ok' flag
  261.         CALL    EMS_13
  262.         MOV    DX,TOTAL_PAGES        ;Load total pages
  263.         XOR    AX,AX             ;Clear return code
  264.         RET
  265. EMS_03        ENDP
  266. ;======================================================================
  267. ;Function 4.  Get handle and allocate pages
  268. ;======================================================================
  269. EMS_04        PROC    NEAR
  270.         ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  271.         OR    BX,BX            ;Check for 0 page request
  272.         JE    EMS_04_ERR        ;If so, error
  273.         CALL    EMS_27            ;Let function 27 do the work
  274. EMS_04_EXIT:    RET
  275. EMS_04_ERR:    MOV    AH,89H            ;attempt to allocate 0 pages
  276.         JMP    SHORT EMS_04_EXIT
  277. EMS_04        ENDP
  278. ;======================================================================
  279. ;Function 5,  Map / Unmap pages.
  280. ;======================================================================
  281. EMS_05        PROC    NEAR
  282.         ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  283.         PUSH    BX
  284.         PUSH    DX
  285.         JC    EMS_05_EXIT        ;carry set, invalid handle
  286.         CMP    AL,3            ;Check for physical page out
  287.         JA    EMS_05_ERR0        ;  of range
  288.         CMP    BX,0FFFFH        ;See if unmap page. If so,
  289.         JNE    EMS_05_S1        ;  save current mapped page
  290.         MOV    BL,AL                   ;  but don't map new page.
  291.         XOR    AX,AX
  292.         XOR    DX,DX                   ;DL:AX=0 indicates no map
  293.         JMP    SHORT EMS_05_S2
  294. EMS_05_S1:    PUSH    AX            ;Save physical page to map
  295.         CALL    EMS_LOG2PHY        ;Convert page into an address
  296.         POP    BX                      ;Put phy page into BX for call
  297.         JC    EMS_05_EXIT        ;If error, exit
  298. EMS_05_S2:    CALL    EMS_EXCH_PAG        ;Map the page
  299.                  XOR    AX,AX            ;Clear return code
  300. EMS_05_EXIT:    POP    DX                      ;Restore registers.
  301.         POP    BX
  302.         RET
  303. EMS_05_ERR0:    MOV    AH,8BH            ;Physical page out of range
  304.         JMP    SHORT EMS_05_EXIT
  305. EMS_05        ENDP
  306. ;======================================================================
  307. ;Function 6,  Deallocate pages.
  308. ;======================================================================
  309. EMS_06        PROC    NEAR
  310.         ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  311.         PUSH    BX
  312.         PUSH    DX
  313.         JC    EMS_06_EXIT        ;carry set, invalid handle
  314.         MOV    BL,0FFH            ;clear all pages
  315.         CALL    EMS_DEALLOC        ;Deallocate memory
  316.         OR    DL,DL            ;handle zero cannot be
  317.         JE    EMS_06_GOOD        ;  deallocated
  318.         PUSH    CS                      ;Deallocate handle
  319.         POP    ES
  320.         ASSUME    ES:CODE
  321.         MOV    DI,HANDLE_ARRAY
  322.         MOV    AX,DX            ;copy handle
  323.         MOV    CX,9            ;convert handle to an index into
  324.         MUL    CX            ;  the handle array.
  325.         ADD    DI,AX
  326.         XOR    AL,AL            ;Erase handle flag and name.
  327.         REP    STOSB
  328. EMS_06_GOOD:    XOR    AX,AX            ;clear return code
  329. EMS_06_EXIT:    POP    DX
  330.         POP    BX
  331.         RET
  332. EMS_06        ENDP
  333. ;======================================================================
  334. ;Function 7.  Get version number
  335. ;======================================================================
  336. EMS_07        PROC    NEAR
  337.         ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  338.         MOV    AX,0040H        ;store ver num and ret code
  339.         RET
  340. EMS_07        ENDP
  341. ;======================================================================
  342. ;Function 8. Save page map.
  343. ;======================================================================
  344. EMS_08        PROC    NEAR
  345.         ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  346.         PUSH    BX
  347.         PUSH    DX
  348.         JC    EMS_08_EXIT        ;Carry set, invalid handle
  349. ;Search the mapping arrays to find an array that is empty.  At the same
  350. ;   time, make sure that the handle doesn't have an array currently saved.
  351.         MOV    SI,MAP_ARRAY_PTR    ;Start search of map arr lbls
  352.         MOV    CX,INT_SAVE_SIZE    ;Search all save map arrays
  353.         XOR    BX,BX            ;Initialize free pointer
  354. EMS_08_L1:    ADD    SI,18            ;Look at next map array
  355.         CMP    WORD PTR [SI],0FFFFh    ;See if free
  356.         JNE    EMS_08_S1
  357.         MOV    DI,SI            ;If so, copy address
  358.         JMP    SHORT EMS_08_S3
  359. EMS_08_S1:    CMP    [SI],DX            ;See if curr hndl used before
  360.         JNE    EMS_08_S2
  361.         MOV    AH,8DH            ;Handle already used for save
  362.         JMP    SHORT EMS_08_EXIT
  363. EMS_08_S2:    LOOP    EMS_08_L1        ;Loop back
  364.         MOV    AH,8CH            ;No room to store page map
  365.         JMP    SHORT EMS_08_EXIT
  366. EMS_08_S3:    PUSH    CS            ;Point ds:si to page array
  367.         POP    ES
  368.         ASSUME ES:CODE            ;Point es:di to save array
  369.         MOV    SI,MAP_ARRAY_PTR
  370.         MOV    [SI],DX            ;Label arrays with handle
  371.         MOV    CX,9
  372.         REP    MOVSW
  373.         XOR    AX,AX            ;Clear return code
  374. EMS_08_EXIT:    POP    DX
  375.                 POP    BX
  376.         RET
  377. EMS_08        ENDP
  378. ;======================================================================
  379. ;Function 9. Restore page map
  380. ;======================================================================
  381. EMS_09        PROC    NEAR
  382.         ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  383.         PUSH    BX
  384.         PUSH    DX
  385.         JC    EMS_09_EXIT        ;carry set, invalid handle
  386. ;find the saved page map in the save array.
  387.         MOV    SI,MAP_ARRAY_PTR
  388.         MOV    CX,INT_SAVE_SIZE
  389. EMS_09_L1:    ADD    SI,18            ;look at next map array
  390.         CMP    [SI],DX            ;See if array label matches
  391.         JE    EMS_09_S1        ;  the handle.
  392.         LOOP    EMS_09_L1
  393.         MOV    AH,8EH            ;no saved page map found
  394.         JMP    SHORT EMS_09_EXIT
  395. ;Now that the saved array has been found, call restore map routine.
  396. EMS_09_S1:    CALL    EMS_15_1        ;restore map
  397.               MOV    WORD PTR [SI],0FFFFh    ;mark saved array as free
  398.         XOR    AX,AX            ;clear return code
  399. EMS_09_EXIT:    POP    DX
  400.         POP    BX
  401.         RET
  402. EMS_09        ENDP
  403. ;======================================================================
  404. ;Function 12, Get Handle Count
  405. ;======================================================================
  406. EMS_12        PROC    NEAR
  407.         ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  408.         MOV    DI,HANDLE_ARRAY        ;point to handle array
  409.         XOR    BX,BX            ;clear count and compare regs
  410.         MOV    CX,TOTAL_HANDLES    ;look at all handles 0 - feh
  411. EMS_12_L1:    CMP    BH,[DI]            ;if handle id = 0 then that
  412.         JE    EMS_12_S1        ;  handle has not been allocated.
  413.         INC    BL            ;Add one to open handle count
  414. EMS_12_S1:    ADD    DI,9            ;Move di to point to next id.
  415.         LOOP    SHORT EMS_12_L1
  416.         XOR    AX,AX            ;clear return code
  417. EMS_12_EXIT:    RET
  418. EMS_12        ENDP
  419. ;======================================================================
  420. ;Function 13 Get Handle pages
  421. ;Entry: dx = handle to search for
  422. ;Exit:  ax = return code.      bx = number of matches found.
  423. ;======================================================================
  424. EMS_13        PROC    NEAR
  425.         ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  426.         PUSH    DI
  427.         JC    EMS_13_EXIT        ;carry set, invalid handle
  428.         MOV    DI,PAG_OWNER_TBL    ;point to owner table
  429.         MOV    CX,TOTAL_PAGES
  430.         XOR    BX,BX            ;Clear page count
  431. EMS_13_LOOP:    CMP    DL,[DI]            ;Compare handle to table
  432.         JNE    EMS_13_SKIP
  433.         INC    BX                      ;Inc count of pages
  434. EMS_13_SKIP:    ADD    DI,3            ;Point to next entry
  435.         LOOP    EMS_13_LOOP
  436.         XOR    AX,AX                   ;Clear return code.
  437. EMS_13_EXIT:    POP    DI
  438.         RET
  439. EMS_13        ENDP
  440. ;======================================================================
  441. ;Function 14. Get All Handle Pages
  442. ;======================================================================
  443. EMS_14        PROC    NEAR
  444.         ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  445.         PUSH    DX
  446.         XOR    DX,DX            ;Handle currently being checked
  447.         XOR    SI,SI            ;SI total open handles counter
  448. EMS_14_L1:    CALL    EMS_CHECK_HDL        ;See if handle active
  449.         CALL    EMS_13            ;Count pages for handle
  450.         JC    EMS_14_S1               ;If bad handle, skip
  451.         INC    SI            ;Add to handle count
  452.         MOV    ES:[DI],DX        ;Write results to the array
  453.         MOV    ES:2[DI],BX
  454. EMS_14_S1:    INC    DX            ;Point to next handle
  455.         ADD    DI,4            ;Incriment array pointer
  456.         CMP    DX,TOTAL_HANDLES    ;Have we check all handles?
  457.         JL    EMS_14_L1        ;No, loop back.
  458.         MOV    BX,SI            ;Get number of active handles
  459.         XOR    AX,AX            ;Clear return code
  460. EMS_14_EXIT:    POP    DX
  461.         RET
  462. EMS_14        ENDP
  463. ;======================================================================
  464. ;Function 15.  Get/Set Page Map
  465. ;======================================================================
  466. EMS_15_TBL    DB    3                  ;Max value of subfunction
  467.                DW    OFFSET EMS_15_0    ;Jump table for subfunctions
  468.         DW    OFFSET EMS_15_1
  469.         DW    OFFSET EMS_15_2
  470.         DW    OFFSET EMS_15_3
  471. EMS_15        PROC    NEAR
  472.         ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  473.         PUSH    BX
  474.         PUSH    DX
  475.         MOV    DS,SS:[BP-8]        ;Get original DS
  476.         ASSUME  DS:NOTHING
  477.         MOV    DI,OFFSET EMS_15_TBL    ;Point to jump table structure
  478.         CALL    EMS_DISPATCHER        ;Dispatch routine calls
  479. EMS_15_EXIT:    POP    DX            ;  subfunction routine.
  480.         POP    BX
  481.         RET
  482. EMS_15        ENDP
  483. ;----------------------------------------------------------------------
  484. ;Function 15.0  Get mapping array
  485. ;----------------------------------------------------------------------
  486. EMS_15_0    PROC    NEAR
  487.         ASSUME  DS:NOTHING,ES:NOTHING
  488.         PUSH    SI
  489.         PUSH    DS
  490.         PUSH    CS
  491.         POP    DS
  492.         ASSUME  DS:CODE
  493.         MOV    SI,MAP_ARRAY_PTR    ;DS:SI points to page array
  494.         MOV    CX,9            ;ES:DI points to destination
  495.         REP    MOVSW            ;Copy mapping array
  496.         XOR    AH,AH
  497.         POP    DS
  498.         POP    SI
  499.         RET
  500. EMS_15_0    ENDP
  501. ;----------------------------------------------------------------------
  502. ;Function 15.1  Set mapping array
  503. ;----------------------------------------------------------------------
  504. EMS_15_1    PROC    NEAR
  505.         ASSUME  DS:NOTHING,ES:NOTHING
  506.         PUSH    SI
  507.         XOR    BX,BX            ;start with logical page 0
  508.         ADD    SI,2            ;move si past the handle ptr
  509. EMS_15_1_L1:    MOV    AX,DS:[SI]        ;get current page address
  510.         MOV    DX,DS:[SI+2]
  511.         PUSH    BX
  512.         CALL    EMS_EXCH_PAG        ;Exchange current window page
  513.         POP    BX                      ;Point si to next address
  514.         ADD    SI,4
  515.         INC    BX
  516.         CMP    BL,3            ;Have we done all 4 pages?
  517.         JLE    EMS_15_1_L1        ;No, loop back
  518.         XOR    AH,AH
  519. EMS_15_1_EXIT:    POP    SI
  520.         RET
  521. EMS_15_1    ENDP
  522. ;----------------------------------------------------------------------
  523. ;Function 15.2  Get & Set mapping array
  524. ;----------------------------------------------------------------------
  525. EMS_15_2    PROC    NEAR
  526.         ASSUME  DS:NOTHING,ES:NOTHING
  527.         PUSH    DI
  528.         CALL    EMS_15_0        ;Save current mapping array
  529.         POP    DI
  530.         CALL    EMS_15_1        ;Set new mapping context
  531.         XOR    AH,AH
  532.         RET
  533. EMS_15_2    ENDP
  534. ;----------------------------------------------------------------------
  535. ;Function 15.3  Get mapping array size
  536. ;----------------------------------------------------------------------
  537. EMS_15_3    PROC    NEAR
  538.         ASSUME  DS:NOTHING,ES:NOTHING
  539.         MOV    AX,0012H        ;18 bytes in the page array
  540.         RET
  541. EMS_15_3    ENDP
  542. ;======================================================================
  543. ;Function 16.  Get/Set Partial Page Map
  544. ;======================================================================
  545. EMS_16_TBL    DB    2            ;Max value of subfunction
  546.               DW    OFFSET EMS_16_0        ;Jump table for subfunctions
  547.         DW    OFFSET EMS_16_1
  548.         DW    OFFSET EMS_16_2
  549. EMS_16        PROC    NEAR
  550.         ASSUME     CS:CODE,DS:CODE,ES:NOTHING
  551.         PUSH    BX
  552.         PUSH    DX
  553.         MOV    DS,SS:[BP-8]        ;Get original DS from stack
  554.         ASSUME     DS:NOTHING
  555.         MOV    DI,OFFSET EMS_16_TBL    ;Point to jump table structure
  556.         CALL    EMS_DISPATCHER        ;Dispatch routine calls
  557. EMS_16_EXIT:    POP    DX            ;  subfunction routine.
  558.         POP    BX
  559.         RET
  560. EMS_16        ENDP
  561. ;----------------------------------------------------------------------
  562. ;Function 16.0  Get mapping array
  563. ;----------------------------------------------------------------------
  564. EMS_16_0    PROC    NEAR
  565.         ASSUME  DS:NOTHING,ES:NOTHING
  566.         MOV    CX,DS:[SI]        ;get count of mappable segs.
  567.         MOV    ES:[DI],CX        ;save count
  568. EMS_16_0_L1:    MOV    AX,DS:2[SI]        ;Get segment to convert
  569.         CALL    EMS_SEG2LOG        ;convert segment onto page #
  570.         JC    EMS_16_0_EXIT
  571.         MOV    ES:2[DI],BX        ;save physical page number
  572.         SAL    BX,1            ;Convert page number
  573.         SAL    BX,1            ;  into offset
  574.         ADD    BX,CS:MAP_ARRAY_PTR
  575.         MOV    AX,CS:2[BX]
  576.         MOV    ES:4[DI],AX        ;save address low
  577.         MOV    AX,CS:4[BX]
  578.         MOV    ES:6[DI],AX        ;save address high
  579.         ADD    DI,6
  580.         INC    SI            ;point to next seg to save
  581.         INC    SI
  582.         LOOP    EMS_16_0_L1
  583.         XOR    AX,AX
  584. EMS_16_0_EXIT:    RET
  585. EMS_16_0    ENDP
  586. ;----------------------------------------------------------------------
  587. ;Function 16.1  Set mapping array
  588. ;----------------------------------------------------------------------
  589. EMS_16_1    PROC    NEAR
  590.         ASSUME  DS:NOTHING,ES:NOTHING
  591.         MOV    CX,DS:[SI]        ;get count of pages
  592. EMS_16_1_L1:    MOV    BX,2[SI]        ;get logical page
  593.         MOV    AX,4[SI]        ;get address of page to
  594.         MOV    DX,6[SI]        ;  restore
  595.         CALL    EMS_EXCH_PAG        ;Exchange current window page
  596.         ADD    SI,6            ;Point si to next page
  597.         LOOP    EMS_16_1_L1        ;No, loop back
  598.         XOR    AX,AX            ;Clear error code
  599. EMS_16_1_EXIT:    RET
  600. EMS_16_1    ENDP
  601. ;----------------------------------------------------------------------
  602. ;Function 16.2  Get partial mapping array size
  603. ;----------------------------------------------------------------------
  604. EMS_16_2    PROC    NEAR
  605.         ASSUME  DS:NOTHING,ES:NOTHING
  606.         MOV    AX,BX            ;get number of pages
  607.         MOV    AH,6            ;6 bytes per page
  608.         MUL    AH
  609.         ADD    AX,2            ;add room for count
  610.         XOR    AH,AH            ;zero return code
  611.         RET
  612. EMS_16_2    ENDP
  613. ;======================================================================
  614. ;Function 17.  Map Multiple Handle Pages
  615. ;======================================================================
  616. EMS_17        PROC    NEAR
  617.         ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  618.         MOV    ES,SS:[BP-8]        ;get pointer to map structure
  619.         CALL    EMS_17_INTERNAL
  620.         RET
  621. EMS_17        ENDP
  622. ;----------------------------------------------------------------------
  623. ;Function 17 (internal).  Used by jump and call routines to map pages.
  624. ;----------------------------------------------------------------------
  625. EMS_17_INTERNAL    PROC    NEAR
  626.         ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  627.         PUSH    BX
  628.         PUSH    DX
  629.         JC    EMS_17_EXIT        ;carry set, invalid handle
  630.         CMP    AL,1            ;no subfunction > 1.
  631.         JA    EMS_17_ERR1
  632.         CMP    CX,4            ;Make sure count < number of
  633.         JA    EMS_17_ERR2        ;  mappable pages.
  634.         MOV    CH,AL            ;save subfunction
  635. EMS_17_L1:    MOV    AX,ES:[SI+2]        ;get physical page number/seg
  636.         OR    CH,CH
  637.         JE    EMS_17_S3        ;if seg address mapping,
  638.         CALL    EMS_SEG2LOG        ;  convert seg addr to number
  639.         JC    EMS_17_EXIT        ;check for error on conversion
  640.         MOV    AL,BL
  641. EMS_17_S3:    MOV    BX,ES:[SI]        ;get logical page number
  642.         CLC                ;handle valid
  643.         PUSH    CX            ;save count
  644.         CALL    EMS_05            ;map page
  645.         POP    CX            ;restore count
  646.         OR    AH,AH            ;check for error
  647.         JNE    EMS_17_EXIT
  648.         ADD    SI,4            ;Move pointers to next
  649.         DEC    CL            ;  mapping structure.
  650.         JNZ    EMS_17_L1
  651.         XOR    AX,AX            ;clear return code
  652. EMS_17_EXIT:    POP    DX
  653.         POP    BX
  654.         RET
  655. EMS_17_ERR1:    MOV    AH,8FH            ;invalid subfunction
  656.         JMP    SHORT EMS_17_EXIT
  657. EMS_17_ERR2:    MOV    AH,8BH            ;Number exceeds mappable pages
  658.         JMP    SHORT EMS_17_EXIT    ;  in the system
  659. EMS_17_INTERNAL    ENDP
  660. ;======================================================================
  661. ;Function 18.  Reallocate Pages
  662. ;======================================================================
  663. EMS_18        PROC    NEAR
  664.         ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  665.         PUSH    BX
  666.         PUSH    DX
  667.         JC    EMS_18_EXIT        ;carry set, invalid handle
  668.         MOV    DI,BX            ;save reallocation count
  669.         PUSH    BX
  670.         CALL    EMS_13            ;get current count
  671.         MOV    CX,BX
  672.         POP    BX            ;get back new count
  673.         SUB    BX,CX
  674.         JG    EMS_18_INCREASE
  675.         JL    EMS_18_REDUCE
  676.         XOR    AH,AH            ;clear return code
  677. EMS_18_EXIT:    POP    DX
  678.         POP    BX
  679.         RET
  680. EMS_18_INCREASE:
  681.         CALL    EMS_ASSIGN
  682.         JMP    SHORT EMS_18_EXIT
  683. EMS_18_REDUCE:    NEG    BX            ;turn into positive number
  684.         CALL    EMS_DEALLOC
  685.         JMP    SHORT EMS_18_EXIT
  686. EMS_18        ENDP
  687. ;======================================================================
  688. ;Function 19. Get/Set Handle Attribute (Not Supported)
  689. ;======================================================================
  690. EMS_19        PROC    NEAR
  691.         ASSUME  CS:CODE,DS:CODE
  692.         CMP    AL,1
  693.         JE    EMS_19_1           ;Set handle attribute.
  694.         CMP    AL,2            ;For subfunctions 0 and 2,
  695.         JG    EMS_19_ERR1        ;  return volatile handle,
  696. EMS_19_GOOD_EXIT:
  697.         XOR    AX,AX                   ;  non-volatile not supp
  698. EMS_19_EXIT:    RET
  699. EMS_19_1:    CALL    EMS_CHECK_HDL        ;See if good handle
  700.         JC    EMS_19_ERR2
  701.         CMP    BL,1             ;See if legal attribute type
  702.         JG     EMS_19_ERR3          ;  or if non-volatile.
  703.         JL    EMS_19_GOOD_EXIT
  704.         MOV    AH,91H            ;function not supported
  705.         JMP    SHORT EMS_19_EXIT
  706. EMS_19_ERR1:    MOV    AH,8FH            ;subfunction invalid
  707.         JMP    SHORT EMS_19_EXIT
  708. EMS_19_ERR2:    MOV    AH,83H            ;invalid handle
  709.         JMP    SHORT EMS_19_EXIT
  710. EMS_19_ERR3:    MOV    AH,90H            ;attribute type not defined.
  711.         JMP    SHORT EMS_19_EXIT
  712. EMS_19        ENDP
  713. ;======================================================================
  714. ;Function 20. Get/Set Handle Name
  715. ;======================================================================
  716. EMS_20        PROC    NEAR
  717.         ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  718.         PUSH    BX
  719.         PUSH    DX
  720.         JC    EMS_20_EXIT        ;carry set, invalid handle
  721.         PUSH    AX            ;find spot for handle
  722.         MOV    BX,CS            ;get code segment
  723.         MOV    AX,DX            ;Compute offset by multipling
  724.         MOV    AH,9            ;  the handle number by the
  725.         MUL    AH            ;  size of each entry (9).
  726.         MOV    DX,AX
  727.         ADD    DX,HANDLE_ARRAY
  728.         INC    DX            ;point dx past the handle used
  729.         POP    AX            ;  flag.
  730.         OR    AL,AL            ;Check for get or set subfun.
  731.         JNE    EMS_20_S1
  732. ;Get Handle Name
  733.         MOV    SI,DX            ;load pointer to handle name
  734.         JMP    SHORT EMS_20_MOV
  735. ;Set Handle Name
  736. EMS_20_S1:    CMP    AL,1            ;Make sure that subfunction
  737.         JNE    EMS_20_ERR1             ;  = 1.
  738.         MOV    DS,SS:[BP-8]            ;Get original DS
  739.         ASSUME  DS:NOTHING
  740.         PUSH    SI
  741.         PUSH    DX
  742.         CALL    EMS_21_1        ;First, search for handle
  743.         POP    DX            ;  with this name. The
  744.         POP    SI            ;  return code must be a0h.
  745.         AND    AH,0FEH            ;  or a1h.
  746.         CMP    AH,0A0H
  747.         JNE    EMS_20_ERR2
  748.         MOV    DI,DX            ;Get back name pointer
  749.         PUSH    CS
  750.         POP    ES
  751.         ASSUME  ES:CODE
  752. EMS_20_MOV:    MOV    CX,8            ;copy name. move 8 bytes
  753.         REP    MOVSB
  754.         XOR    AX,AX            ;clear return code
  755. EMS_20_EXIT:    POP    DX
  756.         POP    BX
  757.         RET
  758. EMS_20_ERR1:    MOV    AH,8FH            ;Invalid subfunction
  759.         JMP    SHORT EMS_20_EXIT
  760. EMS_20_ERR2:    MOV    AH,0A1H            ;Handle already used
  761.         JMP    SHORT EMS_20_EXIT
  762. EMS_20        ENDP
  763. ;======================================================================
  764. ;Function 21. Get Handle directory
  765. ;======================================================================
  766. EMS_21_TBL    DB    2            ;Max value of subfunction
  767.               DW    OFFSET EMS_21_0    ;Jump table for subfunctions
  768.         DW    OFFSET EMS_21_1
  769.         DW    OFFSET EMS_21_2
  770. EMS_21        PROC    NEAR
  771.         ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  772.         MOV    DS,SS:[BP-8]        ;Get original DS
  773.         ASSUME  DS:NOTHING
  774.         MOV    DI,OFFSET EMS_21_TBL
  775.         CALL    EMS_DISPATCHER
  776. EMS_21_EXIT:    RET
  777. EMS_21        ENDP
  778. ;----------------------------------------------------------------------
  779. ;Function 21.0  Get Handle Directory
  780. ;----------------------------------------------------------------------
  781. EMS_21_0    PROC    NEAR
  782.         ASSUME  DS:NOTHING,ES:NOTHING
  783.         PUSH    DX
  784.         PUSH    CS
  785.         POP    DS
  786.         ASSUME  DS:CODE
  787.         MOV    SI,HANDLE_ARRAY
  788.         XOR    AX,AX            ;Clear RC and hndl counter
  789.         MOV    DX,AX            ;Start with handle 0
  790. EMS_21_0_L1:    CMP    BYTE PTR [SI],0        ;Check flag to see if handle
  791.         JE    EMS_21_0_S1        ;  is used.
  792.         MOV    ES:[DI],DX        ;Store handle value
  793.         INC    SI            ;move SI past handle flag
  794.         ADD    DI,2            ;move DI past handle
  795.         MOV    CX,8            ;8 char per handle name
  796.         REP    MOVSB
  797.         INC    AL            ;add to handle count
  798.         JMP    SHORT EMS_21_0_S2
  799. EMS_21_0_S1:    ADD    SI,9            ;move to the next handle
  800. EMS_21_0_S2:    INC    DX            ;check next handle
  801.         CMP    DX,TOTAL_HANDLES    ;last handle?
  802.         JB    EMS_21_0_L1        ;no, loop back
  803.         POP    DX
  804.         RET
  805. EMS_21_0    ENDP
  806. ;----------------------------------------------------------------------
  807. ;Function 21.1  Search for Named Handle
  808. ;----------------------------------------------------------------------
  809. EMS_21_1    PROC    NEAR
  810.         ASSUME  DS:NOTHING
  811.         PUSH    BX
  812.         PUSH    DS            ;copy segment of name
  813.         POP    ES
  814.         ASSUME ES:NOTHING
  815.         MOV    DI,SI
  816.         MOV    CX,8            ;Check for null string. If
  817.         XOR    AL,AL            ;  null, skip scan for dup
  818.         REPE    SCASB            ;  strings.
  819.         JE    EMS_21_1_ERR1
  820.         MOV    CX,CS:TOTAL_HANDLES    ;look at all handles
  821.         PUSH    CS            ;ES:DI -> handle array
  822.         POP    ES            ;DS:SI -> handle name
  823.         ASSUME  ES:CODE
  824.         MOV    BX,SI            ;bx holds handle name ptr
  825.         MOV    AX,CS:HANDLE_ARRAY    ;ax holds handle array ptr
  826.         INC    AX            ;move ax past handle flag
  827.         XOR    DX,DX            ;start handle count at 0
  828. EMS_21_1_L1:    MOV    DI,AX            ;Compare each of the handle
  829.         MOV    SI,BX            ;  names with the new handle
  830.         PUSH    CX
  831.         MOV    CX,8
  832.         REPE    CMPSB
  833.         POP    CX
  834.         JE    EMS_21_1_EXIT        ;If match found print err msg.
  835.         ADD    AX,9            ;move AX to next handle
  836.         INC    DX
  837.         LOOP    EMS_21_1_L1
  838.         MOV    AH,0A0H            ;handle not found
  839.         JMP    SHORT EMS_21_1_EXIT1
  840. EMS_21_1_EXIT:    XOR    AH,AH
  841. EMS_21_1_EXIT1:    POP    BX
  842.         RET
  843. EMS_21_1_ERR1:    MOV    AH,0A1H            ;null handle found
  844.         JMP    SHORT EMS_21_1_EXIT1
  845. EMS_21_1    ENDP
  846. ;----------------------------------------------------------------------
  847. ;Function 21.2  Get Total Handles
  848. ;----------------------------------------------------------------------
  849. EMS_21_2    PROC    NEAR
  850.         ASSUME    DS:NOTHING
  851.         MOV    BX,CS:TOTAL_HANDLES    ;Get number of allowed hdls
  852.         XOR    AX,AX           ;Clear return code.
  853.         RET
  854. EMS_21_2    ENDP
  855. ;======================================================================
  856. ;Function 22. Alter Page Map and Jump
  857. ;======================================================================
  858. EMS_22        PROC    NEAR
  859.         ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  860.         JC    EMS_22_EXIT        ;carry set, invalid handle
  861. ;Map new pages into window
  862.         MOV    DI,SI            ; ES:DI = pointer to map and
  863.         MOV    ES,SS:[BP-8]        ;  jump data
  864.         MOV     SI,ES:[DI]        ;Modify return address on
  865.         MOV    SS:[BP+2],SI        ;  the stack to the address
  866.         MOV     SI,ES:[DI+2]        ;  in the jump structure.
  867.         MOV    SS:[BP+4],SI
  868.         MOV    SI,ES:[DI+5]        ;Get pointer to mapping
  869.         MOV    ES,ES:[DI+7]        ;   structure.
  870.         MOV    CL,ES:[DI+4]        ;get mapping count
  871.         XOR    CH,CH
  872.         CALL    EMS_17_INTERNAL        ;alter page map
  873. EMS_22_EXIT:    RET
  874. EMS_22        ENDP
  875. ;======================================================================
  876. ;Function 23. Alter Page Map and Call
  877. ;======================================================================
  878. EMS_23        PROC    NEAR
  879.         ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  880.         JC    EMS_23_JMP_END          ;carry set, invalid handle
  881.         CMP    AL,2            ;Check for stack size function
  882.         JNE    EMS_23_S1
  883.         MOV    BX,28            ;Say we need 28 bytes
  884.         XOR    AH,AH
  885. EMS_23_JMP_END:    JMP    EMS_23_EXIT
  886. EMS_23_S1:    PUSH    AX            ;Save subfunction
  887. ;Map new pages into window
  888.         MOV    DI,SI            ;get pointer to map and
  889.         MOV    ES,SS:[BP-8]        ;  jump data
  890.         PUSH    ES            ;Save pointer to structure
  891.         PUSH    DI
  892.         XOR    CH,CH
  893.         MOV    CL,ES:[DI+4]        ;get mapping count
  894.         MOV    SI,ES:[DI+5]        ;get pointer to mapping
  895.         MOV    ES,ES:[DI+7]        ;   structure
  896.         PUSH    AX
  897.         CLC                ;indicate good handle
  898.         CALL    EMS_17_INTERNAL        ;alter page map
  899.         OR    AH,AH
  900.         POP    AX            ;Restore AX
  901.         JNE    EMS_23_EXIT
  902. ;Restore values in the registers and call.
  903.         MOV    AX,SS:[BP+6]        ;get flags
  904.         PUSH    AX
  905.         POPF                ;load flags
  906.         MOV    ES,SS:[BP-10]        ;restore ES
  907.         MOV    DS,SS:[BP-8]            ;Restore DS
  908.         MOV    SI,SS:[BP-6]        ;Restore SI
  909.         MOV    DI,SS:[BP-4]        ;Restore DI
  910.         MOV    CX,SS:[BP-2]        ;Restore CX
  911.         ASSUME    DS:NOTHING
  912.         PUSH    BP                      ;Save my base pointer
  913.         MOV    BP,SS:[BP]        ;Restore BP
  914.         MOV    AX,0000            ;Clear return code
  915.         CALL    DWORD PTR DS:[SI]    ;Call.
  916.         POP    AX            ;Get back pointer to stack
  917.         PUSH    BP            ;Save returned BP
  918.         MOV     BP,AX            ;Restore my base pointer
  919.         POP    AX            ;Get back returned BP
  920.         PUSHF                ;Save returned flags
  921.         MOV    [BP-10],ES
  922.         MOV    [BP-8],DS        ;Put reg values on stack
  923.         MOV    [BP-6],SI               ;  to be restored on return
  924.         MOV    [BP-4],DI
  925.         MOV    [BP-2],CX
  926.         POP    CX                 ;Get back returned flags
  927.         MOV    SS:[BP+6],CX
  928.         MOV    SS:[BP],AX        ;Save returned BP
  929.         PUSH    CS
  930.         POP    DS
  931.         ASSUME  DS:CODE
  932. ;Map old pages into window
  933.         POP    DI            ;Get back pointer to structure
  934.         POP    ES
  935.         XOR    CH,CH
  936.         MOV    CL,ES:[DI+9]        ;get mapping count
  937.         MOV    SI,ES:[DI+10]        ;get pointer to mapping
  938.         MOV    ES,ES:[DI+12]        ;   structure
  939.         CLC                ;indicate good handle
  940.         POP    AX            ;Restore subfunction
  941.         CALL    EMS_17_INTERNAL        ;alter page map
  942. EMS_23_EXIT:    RET
  943. EMS_23        ENDP
  944. ;======================================================================
  945. ;Function 24.  Move/Exchange Memory Region
  946. ;======================================================================
  947. EMS_24_SUBFUN    EQU    [BP-1]            ;Saved subfunction
  948. EMS_24_DIR    EQU    [BP-2]            ;Direction flag for move
  949. EMS_24_COUNT    EQU    [BP-6]            ;Amount of memory to move
  950. EMS_24_SRC_PTR    EQU    [BP-10]            ;Source move pointer
  951. EMS_24_DEST_PTR    EQU    [BP-14]            ;Destination move pointer
  952. EMS_24_RET_CODE    EQU    [BP-15]            ;RC for non-fatal error codes
  953. EMS_24        PROC    NEAR
  954.         ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  955.         PUSH    BX            ;Save registers
  956.         PUSH    DX
  957.         MOV    ES,SS:[BP-8]        ;Get DS off original stack
  958.         PUSH    ES            ;Push for local addressability
  959.         PUSH    SI
  960.         PUSH    BP
  961.         MOV    BP,SP            ;Set up pointer to local data
  962.         SUB    SP,18            ;Make room on stack for data
  963.         MOV     EMS_24_SUBFUN,AL        ;Save subfunction
  964.         MOV    BYTE PTR EMS_24_RET_CODE,0
  965.         MOV    AX,ES:[SI]        ;Get count from move struc
  966.         MOV    DX,ES:[SI+2]
  967.         CMP    DX,10H            ;see if region size > 1M
  968.         JB     EMS_24_S0
  969.         MOV    AH,96H            ;region > 1M byte
  970.         JMP    EMS_24_EXIT
  971. EMS_24_S0:    MOV    WORD PTR [EMS_24_COUNT],AX    ;Save count. Compute
  972.         MOV    WORD PTR [EMS_24_COUNT+2],DX    ;  the number of
  973.         MOV    CX,16384                ;  16K pages needed.
  974.         DIV    CX
  975.         MOV    CH,AL            ;Save number of pages
  976.         MOV    CL,DL            ;save remainder
  977. ;Verify handles have the pages assigned. (If Expanded memory.)
  978.         ADD    SI,4            ;move pointer to source descr
  979.         MOV    DI,-10            ;Pointer to src local store
  980.         CALL    EMS_CHECK_MOV
  981.         JC    EMS_24_JMP_EXIT
  982.         PUSH    AX            ;Save source end address
  983.         PUSH    DX
  984.         ADD    SI,7                    ;Point to destination block
  985.         MOV    DI,-14            ;Pointer to dest local store
  986.         CALL    EMS_CHECK_MOV
  987.         POP    DI                      ;Recover source end address
  988.         POP    BX
  989.         JNC    EMS_24_S01              ;If error flag set, exit
  990. EMS_24_JMP_EXIT:
  991.         JMP    EMS_24_EXIT
  992. EMS_24_S01:    MOV    BYTE PTR EMS_24_DIR,0    ;Set direction flag bottom up
  993. ;Check and adjust for overlap if necessary. If exchange, don't allow overlap.
  994.         MOV    CL,BYTE PTR ES:[SI]      ;Get destination memory type
  995.         ADD    CL,BYTE PTR ES:[SI-7]      ;Compare to source memory type
  996.         CMP    CL,1            ;0 = both conv, 1 = diff types,
  997.         JE    EMS_24_MOVEDATA        ;  2 = both expanded.
  998.         JB    EMS_24_S2        ;0, check conv overlap.
  999.         MOV    CX,ES:[SI+1]        ;Get dest handle
  1000.         CMP    CX,ES:[SI-6]        ;Compare to source handle
  1001.         JNE    EMS_24_MOVEDATA        ;Not the same, no overlap
  1002.         MOV    CX,ES:[SI-2]        ;Get source starting page
  1003.         CMP    CX,ES:[SI+5]        ;Compare dest starting page
  1004.         JB    EMS_24_S1          ;If source starts first,
  1005.         JA    EMS_24_S02              ;  bottom up move.
  1006.         MOV    CX,ES:[SI-4]            ;Get source starting offset
  1007.         CMP    CX,ES:[SI+3]            ;Get source starting offset
  1008.         JB    EMS_24_S1        ;Source lower, bottom up move
  1009. EMS_24_S02:    MOV     BX,AX                   ;Copy from top down.
  1010.         MOV     DI,DX            ;Put end addr of Dest in DI,BX
  1011.         SUB    SI,7            ;Point to source descriptor
  1012.         MOV    BYTE PTR EMS_24_DIR,1    ;Set direction top down
  1013. EMS_24_S1:    CMP    DI,ES:[SI+5]        ;Compare end with start addr
  1014.         JB    EMS_24_MOVEDATA        ;No overlap
  1015.         JA    EMS_24_OVERLAP        ;Overlap
  1016.         CMP    BX,ES:[SI+3]        ;Same pages, check offsets
  1017.         JB    EMS_24_MOVEDATA        ;If less, no overlap
  1018.         JMP    SHORT EMS_24_OVERLAP
  1019. ;Check for overlap of conventional memory regions.
  1020. EMS_24_S2:    CMP    DX,DI            ;Compare high word
  1021.         JB    EMS_24_S3        ;dest higher, top down
  1022.         JA    EMS_24_S21              ;Less, bottom up.
  1023.         CMP    AX,BX            ;Compare low word of address
  1024.         JB     EMS_24_S3        ;Jmp if dest addr higher
  1025. EMS_24_S21:    MOV    SI,-14            ;Point to dest descriptor
  1026.         CALL    EMS_24_ADR_CNV
  1027.         XCHG    DI,DX            ;Exchange starting addresses
  1028.         XCHG    BX,AX
  1029.         MOV    SI,-10            ;Point to source descriptor
  1030.         CALL    EMS_24_ADR_CNV
  1031.         MOV    BYTE PTR EMS_24_DIR,1    ;Set direction flag top down
  1032. EMS_24_S3:    SUB    BX,WORD PTR [EMS_24_COUNT]    ;Generate start addr
  1033.         SBB    DI,WORD PTR [EMS_24_COUNT+2]
  1034.         CMP    DX,DI                   ;Compare starting addr with
  1035.         JB    EMS_24_MOVEDATA        ;  end of other block
  1036.         CMP    AX,BX
  1037.         JBE    EMS_24_MOVEDATA
  1038. EMS_24_OVERLAP:    MOV    BYTE PTR EMS_24_RET_CODE,92H    ;Indicate overlap
  1039.         CMP    BYTE PTR EMS_24_SUBFUN,0    ;If exch. don't allow
  1040.         JE    EMS_24_MOVEDATA                 ;  overlap.
  1041.         MOV    AH,97H                ;Error, no overlap
  1042.         JMP    EMS_24_EXIT            ;  on exchange.
  1043. ;Move/Exchange the data
  1044. EMS_24_MOVEDATA:
  1045.         MOV    BX,MAP_ARRAY_PTR    ;Save context of pages 0 & 1
  1046.         PUSH    [BX+8]                  ;Save address for page 1
  1047.         PUSH    [BX+6]
  1048.         PUSH    [BX+4]            ;Save address for page 0
  1049.         PUSH    [BX+2]
  1050.         STD
  1051.         CMP    BYTE PTR EMS_24_DIR,0   ;If moving from top to bottom
  1052.         JNE    EMS_24_MOVE0            ;  set direction flag for move
  1053.         CLD
  1054.         MOV    AX,ES:[SI-4]        ;If move from bottom to top,
  1055.         MOV    DX,ES:[SI-2]                    ;  initialize the
  1056.         MOV    WORD PTR [EMS_24_SRC_PTR],AX    ;  pointers back to
  1057.         MOV    WORD PTR [EMS_24_SRC_PTR+2],DX  ;  the starting
  1058.         MOV    AX,ES:[SI+3]                    ;  addresses.
  1059.         MOV    DX,ES:[SI+5]
  1060.         MOV    WORD PTR [EMS_24_DEST_PTR],AX
  1061.         MOV    WORD PTR [EMS_24_DEST_PTR+2],DX
  1062. EMS_24_MOVE0:    XOR    CX,CX            ;Clear last move count
  1063. EMS_24_MOVELOOP:
  1064.         MOV    ES,[BP+4]        ;Restore move structure
  1065.         MOV    BX,[BP+2]        ;  pointer to ES:BX
  1066.         MOV    DX,ES            ;Save ES
  1067.         MOV     AX,CX            ;Save last count
  1068.         ADD    BX,4                    ;Point to source descriptor
  1069.         XOR    SI,SI            ;Indicate source
  1070.         CALL    EMS_24_MOV_SET
  1071.         PUSH    ES              ;Save source pointer
  1072.         PUSH    DI
  1073.         XCHG    CX,AX            ;save count, restore last cnt
  1074.         MOV    ES,DX            ;Restore ES
  1075.         ADD    BX,7            ;Point to dest mem descriptor
  1076.         MOV    SI,1
  1077.         CALL    EMS_24_MOV_SET         ;Map extended mem if needed
  1078.                 POP     SI            ;Get back source pointer
  1079.         POP    BX            ;Save segment in BX
  1080.         CMP    AX,CX                     ;Get lower count
  1081.         JA    EMS_24_MOVE1
  1082.         MOV    CX,AX
  1083. EMS_24_MOVE1:    MOV    AX,WORD PTR [EMS_24_COUNT]      ;Get move count
  1084.         MOV    DX,WORD PTR [EMS_24_COUNT+2]
  1085.         OR    DX,DX                           ;See if at end of
  1086.         JNE    EMS_24_MOVE2                    ;  count. If so,
  1087.         CMP    AX,CX                           ;  copy only to end
  1088.         JA    EMS_24_MOVE2                    ;  of count.
  1089.         MOV    CX,AX
  1090. EMS_24_MOVE2:    SUB    AX,CX            ;Subtract from count
  1091.         SBB    DX,0
  1092.         PUSH    CX
  1093.         PUSH    AX                      ;Save count
  1094.         PUSH    DX
  1095.         CMP    BYTE PTR EMS_24_SUBFUN,1    ;See if move or exch
  1096.         MOV    DS,BX            ;Time to set DS
  1097.         ASSUME    DS:NOTHING
  1098.         JE    EMS_24_EXCH
  1099.         REP    MOVSB            ;Move that data
  1100.                 JMP    SHORT EMS_24_MOVE3
  1101. EMS_24_EXCH:    MOV    BL,ES:[DI]        ;Get dest byte
  1102.         MOVSB
  1103.         CMP    BYTE PTR EMS_24_DIR,0    ;Check direction flag to
  1104.         JNE    EMS_24_EXCH1            ;  make sure of pointers
  1105.         MOV     DS:[SI-1],BL        ;Move dest byte to source
  1106.         JMP    SHORT EMS_24_EXCH2
  1107. EMS_24_EXCH1:    MOV     DS:[SI+1],BL        ;Move dest byte to source
  1108. EMS_24_EXCH2:    LOOP    EMS_24_EXCH             ;Loop until block exchanged.
  1109. EMS_24_MOVE3:    PUSH    CS                      ;Restore DS altered by move
  1110.         POP    DS
  1111.         ASSUME    DS:CODE
  1112.         POP    DX            ;Get back count
  1113.         POP    AX
  1114.         POP    CX
  1115.         MOV    WORD PTR [EMS_24_COUNT],AX    ;Restore count
  1116.         MOV    WORD PTR [EMS_24_COUNT+2],DX
  1117.         OR    DX,DX
  1118.         JNE    EMS_24_MOVE4            ;See if count has expired.
  1119.         OR    AX,AX
  1120.         JLE    EMS_24_LOOP_DONE
  1121. EMS_24_MOVE4:    JMP    EMS_24_MOVELOOP
  1122. EMS_24_LOOP_DONE:                ;Restore pages 0 and 1.
  1123.         XOR    BX,BX            ;set physical page = 0
  1124.         POP    AX              ;get address of page to
  1125.         POP    DX              ;  restore
  1126.         CALL    EMS_EXCH_PAG        ;Exchange current window page
  1127.         MOV    BX,1             ;set physical page = 1
  1128.         POP    AX              ;get address of page to
  1129.         POP    DX              ;  restore
  1130.         CALL    EMS_EXCH_PAG        ;Exchange current window page
  1131.         MOV    AH,BYTE PTR EMS_24_RET_CODE    ;Get return code
  1132. EMS_24_EXIT:    ADD    SP,18            ;Deallocate local storage
  1133.         POP    BP
  1134.         POP    SI
  1135.         POP    ES
  1136.         POP    DX
  1137.         POP    BX
  1138.         RET
  1139. EMS_24        ENDP
  1140. ;----------------------------------------------------------------------
  1141. ;Convert address to segment offset form
  1142. ;Entry: dx ax - address
  1143. ;          si - pointer to local memory descriptor
  1144. ;----------------------------------------------------------------------
  1145. EMS_24_ADR_CNV    PROC    NEAR
  1146.         PUSH    AX
  1147.         PUSH    DX
  1148.         MOV    CX,16384        ;Convert address to seg:offset
  1149.         DIV    CX
  1150.         MOV    WORD PTR [BP+SI],DX    ;Save offset
  1151.         MOV    CL,10
  1152.         SAL    AX,CL
  1153.         MOV    WORD PTR [BP+SI+2],AX   ;Save segment
  1154.         POP    DX
  1155.         POP    AX
  1156.         RET
  1157. EMS_24_ADR_CNV    ENDP
  1158. ;----------------------------------------------------------------------
  1159. ;Setup ems page for move.
  1160. ;Entry:    al - 0 = source page, 1 = destination page.
  1161. ;       es:bx - pointer to external memory descriptor
  1162. ;          cx - Count used on last move
  1163. ;Exit:  ES:DI - pointer to data to move
  1164. ;          cx - max count before crossing boundry.
  1165. ;----------------------------------------------------------------------
  1166. EMS_24_MOV_SET    PROC    NEAR
  1167.         ASSUME    DS:CODE
  1168.         PUSH    AX
  1169.         PUSH    BX
  1170.         PUSH    DX
  1171.         MOV    DX,SI
  1172.         MOV    SI,-10                  ;Use SI as offset to src_ptr
  1173.         OR    DX,DX
  1174.         JE    EMS_24_MOV_SET_S0
  1175.         SUB    SI,4            ;Point SI to dest_ptr
  1176. EMS_24_MOV_SET_S0:
  1177.         MOV    DH,BYTE PTR ES:[BX]    ;Get memory type
  1178.         MOV    AX,16383        ;Load constants for EMS mem
  1179.         MOV    DI,1
  1180.         OR     DH,DH                 ;Check type of number
  1181.         JNE    EMS_24_MOV_SET_S1    ;1 = EMS memory
  1182.         MOV    DI,1024                 ;Load constants for
  1183.                             ;  conventional memory.
  1184. EMS_24_MOV_SET_S1:
  1185.         CMP    BYTE PTR EMS_24_DIR,0    ;If bottom up move, skip
  1186.         JE    EMS_24_MOV_SET_S3
  1187. ;Top down.
  1188.         SUB    WORD PTR [BP+SI],CX    ;Sub last move from offset
  1189.         JAE    EMS_24_MOV_SET_S2    ;See if end of page
  1190.         MOV    WORD PTR [BP+SI],AX       ;Start at top of next page
  1191.         SUB    WORD PTR [BP+SI+2],DI    ;Point to next page
  1192. EMS_24_MOV_SET_S2:
  1193.         MOV    CX,WORD PTR [BP+SI]    ;Get offset for count
  1194.         INC    CX
  1195.         JMP    EMS_24_MOV_SET_S5
  1196. ;Bottom up
  1197. EMS_24_MOV_SET_S3:
  1198.         ADD    WORD PTR [BP+SI],CX    ;Add last move to offset
  1199.         CMP    WORD PTR [BP+SI],AX       ;See if end of page
  1200.         JBE    EMS_24_MOV_SET_S4
  1201. EMS_24_MOV_SET_S31:
  1202.         MOV    WORD PTR [BP+SI],0     ;Start at bottom of page
  1203.         ADD    WORD PTR [BP+SI+2],DI     ;Point to next page
  1204. EMS_24_MOV_SET_S4:
  1205.         MOV    CX,AX                   ;Compute count to end of page
  1206.         SUB    CX,WORD PTR [BP+SI]
  1207.          INC    CX
  1208. EMS_24_MOV_SET_S5:
  1209.         OR     DH,DH                  ;Check type of number
  1210.         JE    EMS_24_MOV_SET_CONV1    ;If conventional, don't map
  1211.         PUSH    CX            ;Save new count
  1212.         PUSH    DX
  1213.         MOV    AL,DL            ;Pass proper phyical page
  1214.         MOV    DX,WORD PTR ES:[BX+1]    ;Get handle
  1215.         MOV    BX,WORD PTR [BP+SI+2]    ;Put page in proper register
  1216.         PUSHF                ;Save direction flag state
  1217.         CLD                ;Set assumed direction flag
  1218.         CLC                ;Set handle good flag
  1219.         CALL    EMS_05            ;Map page
  1220.         POPF                ;Get back flags
  1221.         POP    DX
  1222.         POP    CX            ;Get count back
  1223.         MOV    AX,WINDOW_SEG        ;Get window segment
  1224.         OR    DL,DL            ;See if source or dest
  1225.         JE    EMS_24_MOV_SET_S6       ;If destination, point to
  1226.         ADD    AX,1024                 ;  2nd page. 1024 paragraphs
  1227. EMS_24_MOV_SET_S6:
  1228.         MOV    ES,AX            ;Set pointer to data
  1229. EMS_24_MOV_SET_EXIT:
  1230.         MOV    DI,WORD PTR [BP+SI]    ;Load offset
  1231.         POP    DX
  1232.         POP    BX
  1233.         POP    AX
  1234.         RET
  1235. EMS_24_MOV_SET_CONV1:
  1236.         MOV    DI,WORD PTR [BP+SI+2]
  1237.         MOV    ES,DI
  1238.         JMP    SHORT EMS_24_MOV_SET_EXIT
  1239. EMS_24_MOV_SET    ENDP
  1240. ;----------------------------------------------------------------------
  1241. ;Check parameters for move or exchange
  1242. ;Entry: es:si - pointer to memory descriptor
  1243. ;       bp+di - pointer to local store descriptor
  1244. ;          ch - number of extended pages needed
  1245. ;          cl - number of bytes into last extended page
  1246. ;Exit:  dx,ax - ending address if conventional
  1247. ;          ax - ending page if expanded
  1248. ;          dx - ending offset if expanded
  1249. ;----------------------------------------------------------------------
  1250. EMS_CHECK_MOV     PROC    NEAR
  1251.         ASSUME  DS:CODE,ES:NOTHING
  1252.         PUSH    BX
  1253.         PUSH    CX
  1254.         PUSH    DI
  1255.         XOR    AX,AX
  1256.         MOV    AL,CH            ;Get number of pages needed
  1257.         MOV    DI,AX            ;Save number of pages in DI
  1258.         XOR    CH,CH
  1259.         MOV    AX,ES:[SI+5]        ;Get segment/page
  1260.         MOV    BX,ES:[SI+3]        ;get offset
  1261.         MOV    DL,ES:[SI]        ;Get memory type
  1262.         OR    DL,DL            ;See if EMS or low memory
  1263.         JE     EMS_CHECK_MOV_CONV    ;jump if low memory
  1264.           CMP    DL,1            ;If not low mem make sure
  1265.         JE     EMS_CHECK_MOV_S1        ;  EMS memory.
  1266.         MOV    AH,98H            ;Invalid memory type
  1267.         JMP    EMS_CHECK_MOV_SET_ERR
  1268. EMS_CHECK_MOV_S1:
  1269.         CMP    BX,3FFFH        ;Check for offset < 16K
  1270.         JA    EMS_CHECK_MOV_ERR1
  1271. ;See if the handle owns enough pages to hold the region.
  1272.         MOV    DX,ES:[SI+1]        ;Get handle
  1273.         PUSH    CX
  1274.         CALL    EMS_CHECK_HDL       ;Verify handle.
  1275.         CALL    EMS_13            ;Get number of pages owned
  1276.         POP    CX                      ;  by handle
  1277.         OR    AH,AH            ;If error, set carry and
  1278.         JNE    EMS_CHECK_MOV_SET_ERR    ;  return.
  1279.         MOV    DX,BX            ;save number of pages
  1280.         MOV    BX,ES:[SI+5]        ;Get logical page number
  1281.         MOV    AX,DI            ;Copy number of pages needed
  1282.         ADD    AX,BX            ;Add starting page.
  1283.         ADD    CX,ES:[SI+3]        ;Add start offset to remainder
  1284.         DEC    CX                      ;  of the num of pages needed.
  1285.         CMP    CX,16384
  1286.         JL    EMS_CHECK_MOV_S4    ;If rem+offset > 16K add a
  1287.         INC    AX            ;  page to the num needed.
  1288.         SUB    CX,16384
  1289. EMS_CHECK_MOV_S4:
  1290.         CMP    AX,DX            ;Compare to total number of
  1291.         JG    EMS_CHECK_MOV_ERR3    ;  pages.
  1292.         MOV    DX,CX            ;Copy ending offset
  1293.         XCHG    AX,DX            ;Exchange offset and segment
  1294. EMS_CHECK_MOV_EXIT:
  1295.         CLC                ;Clear error flag
  1296. EMS_CHECK_MOV_EXIT1:
  1297.         POP    DI                      ;Restore registers
  1298.         MOV    [BP+DI],AX        ;Save offset
  1299.         MOV    [BP+DI+2],DX        ;Save segnent/page
  1300.         POP    CX
  1301.         POP    BX
  1302.         RET
  1303. EMS_CHECK_MOV_CONV:
  1304.         MOV    CX,16            ;convert segment into address
  1305.         MUL    CX
  1306.         ADD    AX,BX            ;Add offset
  1307.         ADC    DX,0
  1308.         ADD    AX,WORD PTR [EMS_24_COUNT]    ;Add len to start addr
  1309.         ADC    DX,WORD PTR [EMS_24_COUNT+2]
  1310.         SUB    AX,1            ;Decriment count
  1311.         SBB    DX,0
  1312.         JMP    SHORT EMS_CHECK_MOV_EXIT
  1313. EMS_CHECK_MOV_ERR1:
  1314.         MOV    AH,95H            ;offset too large
  1315. EMS_CHECK_MOV_SET_ERR:
  1316.         STC                         ;Indicate error
  1317.         JMP    SHORT EMS_CHECK_MOV_EXIT1
  1318. EMS_CHECK_MOV_ERR3:
  1319.         MOV    AH,93H            ;Not enough pages
  1320.         JMP    SHORT EMS_CHECK_MOV_SET_ERR
  1321. EMS_CHECK_MOV ENDP
  1322. ;======================================================================
  1323. ;Function 25. Get Mappable Physical Address Array
  1324. ;======================================================================
  1325. EMS_25        PROC    NEAR
  1326.         ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  1327.         CMP    AL,1            ;assure subfunction 0 or 1.
  1328.         JB    EMS_25_S1
  1329.         JE     EMS_25_EXIT
  1330.                 MOV    AH,8FH            ;Unknown subfunction
  1331.         JMP    SHORT EMS_25_EXIT1
  1332. EMS_25_S1:    MOV    AX,WINDOW_SEG
  1333.         XOR    CX,CX
  1334. EMS_25_L1:    MOV    ES:[DI],AX        ;write segment
  1335.         MOV    ES:2[DI],CX        ;write segment number
  1336.         ADD    AX,1024         ;Point to next segment
  1337.         ADD    DI,4
  1338.         INC    CX                      ;Indicate next page
  1339.         CMP    CX,3
  1340.         JLE    EMS_25_L1
  1341. EMS_25_EXIT:    MOV    WORD PTR SS:[BP-2],4    ;replace saved CX with 4
  1342.         XOR    AX,AX            ;clear return code
  1343. EMS_25_EXIT1:    RET
  1344. EMS_25        ENDP
  1345. ;======================================================================
  1346. ;Function 26.  Get Expanded Memory Hardware Information
  1347. ;======================================================================
  1348. EMS_26        PROC    NEAR
  1349.         ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  1350.         CMP    OS_ENABLED,1        ;Are OS funcctions enabled?
  1351.         JNE    EMS_26_ERR1             ;No, exit
  1352.         CMP    AL,1                    ;Subfunction 1, get page cnt
  1353.         JB    EMS_26_0         ;Jmp to subfunction 0
  1354.         JA    EMS_26_ERR2        ;If > 1, invalid subfunction.
  1355. EMS_26_1:    CALL    EMS_03            ;Since raw page = normal page,
  1356.         JMP    SHORT EMS_26_EXIT       ;  get normal page count.
  1357. EMS_26_0:    XOR    CX,CX
  1358.         MOV    WORD PTR ES:[DI],1024   ;16K pages (1024 paragraphs)
  1359.         MOV    ES:2[DI],CX        ;No alternate register sets
  1360.         CALL    EMS_15_3        ;Get context area size
  1361.         MOV    ES:4[DI],AX
  1362.         MOV    ES:6[DI],CX        ;No DMA channels
  1363.         MOV    ES:8[DI],CX        ;DMA channel operation
  1364.         XOR    AX,AX            ;clear return code
  1365. EMS_26_EXIT:    RET
  1366. EMS_26_ERR1:    MOV    AH,0A4H            ;operating system denied
  1367.         JMP    SHORT EMS_26_EXIT    ;  access.
  1368. EMS_26_ERR2:    MOV    AH,8FH            ;Invalid subfunction
  1369.         JMP    SHORT EMS_26_EXIT
  1370. EMS_26        ENDP
  1371. ;======================================================================
  1372. ;Function 27.  Get handle and allocate pages
  1373. ;======================================================================
  1374. EMS_27        PROC    NEAR
  1375.         ASSUME  DS:CODE,ES:NOTHING
  1376.         PUSH    BX            ;Save register
  1377.         CMP    BX,TOTAL_PAGES        ;Make sure request is not out
  1378.         JLE    EMS_27_S1        ;  of range.
  1379.         MOV    AH,87H            ;Not enough pages in system
  1380.         JMP    SHORT EMS_27_EXIT
  1381. EMS_27_S1:    PUSH    BX            ;save num. of pages to alloc
  1382.         XOR    DX,DX            ;search for handle =-1 (unaloc)
  1383.         DEC    DX
  1384.         CLC
  1385.         CALL    EMS_13            ;get unallocated page count.
  1386.         POP    CX
  1387.         CMP    BX,CX            ;check for enough free pages
  1388.         JL    EMS_27_ERR1
  1389.         MOV    DI,HANDLE_ARRAY        ;Assign handle
  1390.         XOR    AX,AX            ;search for free handles
  1391.         MOV    DX,AX            ;dx=0 at start of hndl search
  1392. EMS_27_L1:    CMP    AL,[DI]            ;if handle id = 0 then that
  1393.         JE    EMS_27_S2        ;  hndl has not been allocated.
  1394.         ADD    DI,9            ;Move di to point to next id.
  1395.         INC    DX
  1396.         CMP    DX,TOTAL_HANDLES    ;have we searched all handles?
  1397.         JB    EMS_27_L1
  1398.         MOV    AH,85H            ;no free handles
  1399.         JMP    SHORT EMS_27_EXIT
  1400. EMS_27_S2:    DEC    BYTE PTR [DI]        ;indicate that handle is used
  1401.         MOV    BX,CX
  1402.         CALL    EMS_ASSIGN        ;alloc pages, dx = new handle
  1403. EMS_27_EXIT:    POP    BX               ;Restore register
  1404.         RET
  1405. EMS_27_ERR1:    MOV    AH,88H
  1406.         JMP    SHORT EMS_27_EXIT
  1407. EMS_27        ENDP
  1408. ;======================================================================
  1409. ;Function 28. Alternate Map Register Set
  1410. ;======================================================================
  1411. EMS_28_TBL    DB    8                  ;Subfunction limit
  1412.               DW    OFFSET EMS_28_0    ;Jump table for subfunctions
  1413.         DW    OFFSET EMS_28_1
  1414.         DW    OFFSET EMS_28_2
  1415.         DW    OFFSET EMS_28_3
  1416.         DW    OFFSET EMS_28_4
  1417.         DW    OFFSET EMS_28_3
  1418.         DW    OFFSET EMS_28_6
  1419.         DW    OFFSET EMS_28_6
  1420.         DW    OFFSET EMS_28_6
  1421. EMS_28        PROC    NEAR
  1422.         ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  1423.         CMP    OS_ENABLED,1        ;See if function enabled
  1424.         JNE    EMS_28_ERR1
  1425.         MOV    DI,OFFSET EMS_28_TBL
  1426.         CALL    EMS_DISPATCHER
  1427. EMS_28_EXIT:    RET
  1428. EMS_28_ERR1:    MOV    AH,0A4H            ;operating system denied
  1429.         JMP    SHORT EMS_28_EXIT    ;  access.
  1430. EMS_28        ENDP
  1431. ;----------------------------------------------------------------------
  1432. ;Function 28.0  Get Alternate Map Register Set
  1433. ;----------------------------------------------------------------------
  1434. EMS_28_0    PROC    NEAR
  1435.         PUSH    DX
  1436.         MOV    ES,ALT_MAP_PTRS        ;Get pointer
  1437.         MOV    DI,ALT_MAP_PTRO
  1438.         MOV    SS:[BP-10],ES
  1439.         OR    DI,DI            ;See if it is zero
  1440.         JNE    EMS_28_0_S1
  1441.         MOV    CX,ES            ;If so, exit without saving
  1442.         OR    CX,CX            ;  page map array.
  1443.         XOR    AX,AX            ;Clear return code
  1444.         JE    EMS_28_0_EXIT
  1445. EMS_28_0_S1:    PUSH    DI            ;save original pointer
  1446.         CALL    EMS_15_0        ;copy page map
  1447.         POP    DI            ;The return code will be
  1448. EMS_28_0_EXIT:    XOR    BL,BL                   ;  set by Function 15.0
  1449.         POP    DX                      ;Indicate non-support for
  1450.         RET                             ;  alternate mapping regs.
  1451. EMS_28_0    ENDP
  1452. ;----------------------------------------------------------------------
  1453. ;Function 28.1  Set Alternate Map Register Set
  1454. ;----------------------------------------------------------------------
  1455. EMS_28_1    PROC    NEAR
  1456.         PUSH    BX
  1457.         PUSH    DX
  1458.         OR    BL,BL            ;check bl = 0
  1459.         JNE    EMS_28_1_ERR
  1460.         MOV    ALT_MAP_PTRS,ES        ;Save mapping pointer
  1461.         MOV    ALT_MAP_PTRO,DI
  1462.         OR    DI,DI            ;See if it is zero
  1463.         JNE    EMS_28_1_S1
  1464.         MOV    CX,ES            ;If so, exit without restoring
  1465.         OR    CX,CX            ;  page map array.
  1466.         JE    EMS_28_1_EXIT
  1467. EMS_28_1_S1:    PUSH    DS
  1468.         MOV    SI,ES            ;Put pointer into ds:si for
  1469.         MOV    DS,SI            ;  function 15.1 call.
  1470.         ASSUME  DS:NOTHING
  1471.         MOV    SI,DI           ;DS:SI = ES:DI
  1472.         CALL    EMS_15_1        ;Restore page map
  1473.         POP    DS
  1474.         ASSUME  DS:CODE
  1475. EMS_28_1_EXIT:    POP    DX
  1476.         POP    BX
  1477.         RET
  1478. EMS_28_1_ERR:    MOV    AH,9CH            ;Alternate map register
  1479.         JMP    SHORT EMS_28_EXIT    ;  sets not supported.
  1480. EMS_28_1    ENDP
  1481. ;----------------------------------------------------------------------
  1482. ;Function 28.2  Get Alternate Map Save Array Size
  1483. ;----------------------------------------------------------------------
  1484. EMS_28_2    PROC    NEAR
  1485.         CALL    EMS_15_3        ;Get save array size.
  1486.         MOV    DX,AX
  1487.         RET
  1488. EMS_28_2    ENDP
  1489. ;----------------------------------------------------------------------
  1490. ;Function 28.3 and 28.5  Deallocate Map Register Set
  1491. ;----------------------------------------------------------------------
  1492. EMS_28_3    PROC    NEAR
  1493.         XOR    BL,BL            ;set bl = 0
  1494.         XOR    AX,AX
  1495.         RET
  1496. EMS_28_3    ENDP
  1497. ;----------------------------------------------------------------------
  1498. ;Function 28.4  Deallocate Alternate Map Register Set
  1499. ;----------------------------------------------------------------------
  1500. EMS_28_4    PROC    NEAR
  1501.         OR    BL,BL            ;See if zero page indicated
  1502.         JNE    EMS_28_4_ERR1        ;  if not, error
  1503.         XOR    AX,AX            ;Clear return code.
  1504.         MOV    ALT_MAP_PTRS,AX        ;Clear mapping pointer
  1505.         MOV    ALT_MAP_PTRO,AX
  1506. EMS_28_4_EXIT:    RET
  1507. EMS_28_4_ERR1:    MOV    AH,9CH            ;Alt register sets not
  1508.         JMP    SHORT EMS_28_4_EXIT    ;  supported
  1509. EMS_28_4    ENDP
  1510. ;----------------------------------------------------------------------
  1511. ;Function 28.6-28.8  Unsupported Subfunctions
  1512. ;----------------------------------------------------------------------
  1513. EMS_28_6    PROC    NEAR
  1514.         OR    BL,BL            ;see if zero page indicated
  1515.         JNE    EMS_28_6_ERR1        ;if not, error
  1516.         XOR    AX,AX            ;clear return code.
  1517. EMS_28_6_EXIT:    RET
  1518. EMS_28_6_ERR1:    MOV    AH,9CH            ;Alt register sets not
  1519.         JMP    SHORT EMS_28_6_EXIT    ;  supported
  1520. EMS_28_6    ENDP
  1521. ;======================================================================
  1522. ;Function 30.  OS/E Functions
  1523. ;======================================================================
  1524. EMS_30        PROC    NEAR
  1525.         PUSH    DX
  1526.         CMP    OS_PASS_LOW,0
  1527.         JNE    EMS_30_S1
  1528.         CMP    OS_PASS_HIGH,0
  1529.         JE    EMS_30_S2        ;first call, create password.
  1530. EMS_30_S1:    CMP    OS_PASS_LOW,BX        ;Check password
  1531.         JNE    EMS_30_ERR1
  1532.         CMP    OS_PASS_HIGH,CX
  1533.         JNE    EMS_30_ERR1
  1534.         JMP    SHORT EMS_30_S3
  1535. EMS_30_S2:    PUSH    AX            ;Read the system time using
  1536.         XOR    AH,AH            ;  bios int 1A function 00.
  1537.         INT    1AH
  1538.         MOV    AX,DX            ;copy low word of time
  1539.         INC    CX            ;multiply by high word. Inc
  1540.         MUL    CX            ;to assure count <> 0.
  1541.         MOV    OS_PASS_LOW,AX
  1542.         MOV    OS_PASS_HIGH,DX
  1543.         MOV    BX,AX                   ;Return password in BX,CX
  1544.         MOV    SS:[BP-2],DX        ;Update CX on stack
  1545.         POP    AX            ;get back subfunction
  1546. EMS_30_S3:    CMP    AL,2            ;return key function
  1547.         JNE    EMS_30_S4
  1548.         XOR    AX,AX            ;Clear return code
  1549.         MOV    OS_PASS_LOW,AX          ;Clear password
  1550.         MOV    OS_PASS_HIGH,AX
  1551.         MOV    OS_ENABLED,1        ;set op system flag
  1552.         JMP    SHORT EMS_30_EXIT
  1553. EMS_30_S4:    CMP    AL,1            ;Disable op system functions
  1554.         JNE    EMS_30_S5
  1555.         MOV    OS_ENABLED,0        ;Clear flag
  1556.         JMP    SHORT EMS_30_EXIT
  1557. EMS_30_S5:    OR    AL,AL            ;Enable op system functions
  1558.         JNE    EMS_30_ERR2
  1559.         MOV    OS_ENABLED,1        ;Set flag
  1560. EMS_30_EXIT:    XOR    AX,AX
  1561. EMS_30_EXIT1:    POP    DX
  1562.         RET
  1563. EMS_30_ERR1:    MOV    AH,0A4H            ;Access denied
  1564.         JMP    SHORT EMS_30_EXIT1
  1565. EMS_30_ERR2:    MOV    AH,8FH            ;Subfunction not defined
  1566.         JMP    SHORT EMS_30_EXIT1
  1567. EMS_30        ENDP
  1568. ;======================================================================
  1569. ;Unsupported Function
  1570. ;======================================================================
  1571. EMS_UNSP    PROC    NEAR
  1572.         ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  1573.         MOV    AH,91H            ;Feature not supported.
  1574.         RET
  1575. EMS_UNSP    ENDP
  1576. ;-----------------------------------------------------------------------------
  1577. ;Convert segment address into logical page number
  1578. ;Entry: ax - segment address to convert  EXIT: bl - logical page number
  1579. ;-----------------------------------------------------------------------------
  1580. EMS_SEG2LOG    PROC    NEAR
  1581.         ASSUME  CS:CODE,DS:NOTHING,ES:NOTHING
  1582.         PUSH    CX
  1583.         PUSH    DX
  1584.         XOR    BX,BX            ;clear logical sector number
  1585.         MOV    DX,CS:WINDOW_SEG
  1586.         MOV    CX,4
  1587. EMS_SEG2_L1:    CMP    AX,DX
  1588.         JE    EMS_SEG2_FND
  1589.         ADD    DX,400H
  1590.         INC    BX
  1591.         LOOP    EMS_SEG2_L1
  1592.         MOV    AH,8BH            ;segment not valid
  1593.         STC
  1594.         JMP    SHORT EMS_SEG2_EXIT
  1595. EMS_SEG2_FND:    CLC
  1596. EMS_SEG2_EXIT:    POP    DX
  1597.         POP    CX
  1598.         RET
  1599. EMS_SEG2LOG    ENDP
  1600. ;------------------------------------------------------------------------
  1601. ;EMS convert logical page to address
  1602. ;Entry: bx = logical page  dx = handle of page owner
  1603. ;Exit: dx,ax - absolute address of page. carry set - page not found
  1604. ;------------------------------------------------------------------------
  1605. EMS_LOG2PHY    PROC    NEAR
  1606.         ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  1607.         PUSH    DI
  1608.         MOV    DI,PAG_OWNER_TBL    ;Point to page owner table
  1609.         MOV    CX,TOTAL_PAGES        ;Check entry for each page
  1610. EMS_LOG2P_L1:    CMP    BYTE PTR [DI],DL    ;See if owned by handle
  1611.         JNE    EMS_LOG2P_S1
  1612.         CMP    WORD PTR [DI+1],BX    ;See if this is the page
  1613.         JE    EMS_LOG2P_S2        ;  we have been looking for.
  1614. EMS_LOG2P_S1:    ADD    DI,3
  1615.         LOOP    SHORT EMS_LOG2P_L1
  1616.         MOV    AH,8AH            ;page out of range for handle
  1617.         STC
  1618.         JMP    SHORT EMS_LOG2PHY_EXIT
  1619. EMS_LOG2P_S2:    SUB    DI,PAG_OWNER_TBL    ;compute the phy page address
  1620.         MOV    AX,DI
  1621.         XOR    DX,DX            ;Clear high word
  1622.         MOV    CX,3            ;Divide by size of each entry
  1623.         DIV    CX
  1624.         MOV    CX,16384        ;Mul page number by size of
  1625.         MUL    CX                      ;  page.
  1626.         ADD    AX,EXTEND_ADRL          ;Add starting address
  1627.         ADC    DL,EXTEND_ADRH
  1628.         XOR    DH,DH
  1629.         CLC                ;clear error flag
  1630. EMS_LOG2PHY_EXIT:
  1631.         POP    DI
  1632.         RET
  1633. EMS_LOG2PHY    ENDP
  1634. ;------------------------------------------------------------------------
  1635. ;EMS Assign pages  bx = number of pages needed  dx = handle to assign pages.
  1636. ;------------------------------------------------------------------------
  1637. EMS_ASSIGN    PROC    NEAR
  1638.         ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  1639.         CMP    AX,TOTAL_PAGES        ;see if enough total pages
  1640.         JG    EMS_ASSIGN_ERR2
  1641.         PUSH    DX            ;save handle
  1642.         PUSH    BX            ;save pages to add
  1643.         MOV    DX,0FFFFH        ;load unassigned handle
  1644.         CLC                             ;Get number of unassigned
  1645.         CALL    EMS_13                  ;  pages.
  1646.         POP    AX            ;Get back number of pages
  1647.         POP    DX            ;Get back handle
  1648.         CMP    BX,AX            ;are there enough pages?
  1649.         JL     EMS_ASSIGN_ERR1        ;No, return error code.
  1650.         PUSH    AX            ;Save number of pages to alloc
  1651.         CLC                ;Set handle found flag
  1652.         CALL    EMS_13            ;Get number of pages assigned
  1653.         POP    AX                      ;Get back num pages requested
  1654.         MOV    DI,PAG_OWNER_TBL    ;point to page owner table
  1655.         MOV    CX,TOTAL_PAGES        ;Get size of the array
  1656.         INC    CX            ;Make sure loop complete
  1657. EMS_ASSIGN_L1:    OR    AX,AX            ;See if we have assigned
  1658.         JE    EMS_ASSIGN_S2        ;  enough pages.
  1659.         CMP    BYTE PTR [DI],0FFH    ;see if page is unowned
  1660.         JNE    EMS_ASSIGN_S1        ;Page owned, try another.
  1661.         MOV    [DI],DL            ;if so, assign it to the hndl
  1662.         MOV    [DI+1],BX        ;Assign page number
  1663.         INC    BX            ;inc page number to assign
  1664.         DEC    AX            ;one less page needed.
  1665. EMS_ASSIGN_S1:    ADD    DI,3            ;point to the next page entry
  1666.         LOOP    EMS_ASSIGN_L1
  1667. EMS_ASSIGN_ERR1:
  1668.         MOV    AH,88H            ;not enough unallocated pages
  1669.         STC                ;set error flag
  1670.         JMP    SHORT EMS_ASSIGN_EXIT
  1671. EMS_ASSIGN_ERR2:
  1672.         MOV    AH,87H            ;not enough pages in system
  1673.         STC                ;set error flag
  1674.         JMP    SHORT EMS_ASSIGN_EXIT
  1675. EMS_ASSIGN_S2:    CLC
  1676.         XOR    AX,AX            ;Clear return code.
  1677. EMS_ASSIGN_EXIT:
  1678.         RET
  1679. EMS_ASSIGN    ENDP
  1680. ;------------------------------------------------------------------------
  1681. ;EMS Deallocate pages
  1682. ;Entry: dx = handle
  1683. ;       bl = number of pages to deallocate
  1684. ;------------------------------------------------------------------------
  1685. EMS_DEALLOC    PROC    NEAR
  1686.         ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  1687.         CMP    BL,0FFH            ;See if clear all
  1688.         JNE    EMS_DEALLOC_S0
  1689.         XOR    BX,BX
  1690.         JMP    SHORT EMS_DEALLOC_S1
  1691. EMS_DEALLOC_S0:    XOR    BH,BH
  1692.         PUSH    BX            ;Save num of pages to dealloc
  1693.         CLC
  1694.         CALL    EMS_13            ;Get num of pages owned
  1695.         POP    AX            ;Get back num pages to dealloc
  1696.         SUB    BX,AX            ;Sub dealloc from total
  1697. EMS_DEALLOC_S1:    MOV    DI,PAG_OWNER_TBL    ;Point to the page owner table
  1698.         MOV    CX,TOTAL_PAGES
  1699. EMS_DEALLOC_L1:    CMP    [DI],DL            ;compare handle
  1700.         JNE    EMS_DEALLOC_S2        ;if not, keep looking
  1701.         CMP    [DI+1],BX        ;compare page number if above
  1702.         JB     EMS_DEALLOC_S2        ;  new limit, erase.  Else,
  1703.         MOV    BYTE PTR [DI],0FFH    ;  keep looking
  1704.         MOV    WORD PTR [DI+1],0FFFFH
  1705. EMS_DEALLOC_S2:    ADD    DI,3            ;Point to next entry
  1706.         LOOP    EMS_DEALLOC_L1
  1707. EMS_DEALLOC_EXIT:
  1708.         XOR    AH,AH                   ;Clear return code.
  1709.         RET
  1710. EMS_DEALLOC    ENDP
  1711. ;-----------------------------------------------------------------------------
  1712. ;EMS Subfunction dispatcher
  1713. ;Entry: DI = pointer to jump table structure
  1714. ;-----------------------------------------------------------------------------
  1715. EMS_DISPATCHER    PROC    NEAR
  1716.         ASSUME  CS:CODE,DS:NOTHING,ES:NOTHING
  1717.         CMP    AL,CS:[DI]            ;Compare subfunction to limit
  1718.         JA    EMS_DIS_ERR1        ;If above, error.
  1719.         PUSH    BX               ;Save BX
  1720.         MOV    BL,AL            ;Convert subfunction to
  1721.         XOR    BH,BH                   ;  jump address.
  1722.         SHL    BX,1
  1723.         ADD    BX,DI               ;Add offset into jump table
  1724.         INC    BX            ;Skip past limit
  1725.         MOV    DI,BX            ;Copy jump address pointer
  1726.         POP    BX                 ;Restore BX
  1727.         PUSH    CS:[DI]            ;Save jump address
  1728.         MOV    DI,SS:[BP-4]        ;Restore DI
  1729.         RETN                            ;Jump to subfunction code.
  1730. EMS_DIS_ERR1:    MOV    AH,8FH                  ;Illegal subfunction
  1731.         STC                             ;Set error flag
  1732.         RET
  1733. EMS_DISPATCHER    ENDP
  1734. ;-----------------------------------------------------------------------------
  1735. ;EMS Check Handle
  1736. ;Entry: dx = handle to check  Exit: zero flag set - handle not found, ah = 83h
  1737. ;-----------------------------------------------------------------------------
  1738. EMS_CHECK_HDL    PROC    NEAR
  1739.         ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  1740.         PUSH    DX
  1741.         PUSH    BX
  1742.         OR    DH,DH            ;dh must be 0 for valid handle
  1743.         JNE    EMS_CHECK_ERROR
  1744.         XCHG    AX,DX            ;Save ax
  1745.         MOV    AH,9            ;Convert handle into an index
  1746.         MUL    AH            ;  into the array
  1747.         MOV    BX,AX            ;copy to base register
  1748.         ADD    BX,HANDLE_ARRAY        ;add base address of array
  1749.         MOV    AX,DX            ;restore ax
  1750.         CMP    BYTE PTR [BX],0        ;If byte<>0, then good handle
  1751.         JE    EMS_CHECK_ERROR
  1752.         CLC                ;clear error flag
  1753. EMS_CHECK_EXIT:    POP    BX
  1754.         POP    DX
  1755.         RET
  1756. EMS_CHECK_ERROR:
  1757.         MOV    AH,83H            ;load error return code in ah
  1758.         STC                ;set error flag
  1759.         JMP    SHORT EMS_CHECK_EXIT
  1760. EMS_CHECK_HDL    ENDP
  1761. ;------------------------------------------------------------------------
  1762. ;EMS exchange page
  1763. ;Entry: bl = window page to map    dl,ax = absolute address of page to map.
  1764. ;------------------------------------------------------------------------
  1765. EMS_EXCH_PAG     PROC    NEAR
  1766.         ASSUME  CS:CODE,DS:NOTHING,ES:NOTHING
  1767.         PUSH    CX
  1768.         PUSH    SI
  1769.         PUSH    DS
  1770.         PUSH    ES
  1771.         PUSH    CS            ;point DS, ES to code segment
  1772.         POP    DS
  1773.         ASSUME     DS:CODE,ES:CODE
  1774.          PUSH    DEST.BASE_ADRL       ;Save GTD data in case a
  1775.          PUSH    SOURCE.BASE_ADRL        ;  reentrant call is made.
  1776.          MOV    CH,DEST.BASE_ADRH
  1777.          MOV    CL,SOURCE.BASE_ADRH
  1778.          PUSH    CX
  1779.          MOV    DI,OFFSET WINDOW_ADDR_BASE    ;Point to window addr
  1780.         MOV    SI,MAP_ARRAY_PTR    ;Point to mapping array.
  1781.         INC    SI
  1782.         INC    SI
  1783.         XOR    BH,BH            ;Clear high byte of page num
  1784. ;Check to see if previous process was interrupted. If so, complete last move.
  1785.         PUSH    BX                      ;Save page number
  1786.         MOV    BL,MOVE_BUSY_FLAG    ;If not 0, this flag contains
  1787.         OR     BL,BL            ;  the page that was being
  1788.         JE    EMS_EXCH_NOT_BUSY    ;  moved when the driver was
  1789.         DEC    BL            ;  interrupted.
  1790.         PUSH    AX                    ;Save new address for a moment
  1791.         PUSH    DX
  1792.                  MOV    AX,[DI+BX]             ;Load window address into
  1793.         MOV    DL,[DI+BX+2]        ;  destination registers.
  1794.                 MOV     CX,SAVED_ADDR_LOW       ;Load physical page address
  1795.         MOV     DH,SAVED_ADDR_HIGH      ;  into source registers.
  1796.                 CALL    EMS_MOVE_DATA        ;Move memory
  1797.         MOV    MOVE_BUSY_FLAG,0    ;  busy flag.
  1798.         POP    DX            ;Get back new address
  1799.         POP    AX
  1800. EMS_EXCH_NOT_BUSY:
  1801.         POP    BX                      ;Get back page number
  1802.         SAL    BX,1                    ;Convert page number into
  1803.         SAL    BX,1                    ;  array index.
  1804.         MOV    DH,1
  1805.         CMP    AX,[SI+BX]        ;Check to see if page to be
  1806.         JNE    EMS_EXCH_S1        ;  is already mapped in the
  1807.         CMP    DX,[SI+BX+2]        ;  page.
  1808.         JE    EMS_EXCH_EXIT        ;If so, exit.
  1809. EMS_EXCH_S1:    PUSH    AX            ;Save new page address
  1810.         PUSH    DX
  1811. ;Check to see if the address requested has already been mapped.
  1812.         MOV     AX,[SI+BX]              ;Load address of current page
  1813.         MOV     DX,[SI+BX+2]            ;  into destination registers.
  1814.         OR    DH,DH            ;See if this is the primary
  1815.         JE     LOAD_PAGE        ;  page. No, don't save.
  1816.         XOR    DH,DH            ;Search for secondary pages
  1817.         CALL    EMS_CHK_LOCAL        ;Check for same page locally
  1818.         JC     LOAD_PAGE
  1819. ;Save page currently mapped.
  1820. STORE_PAGE:     MOV     CX,[DI+BX]              ;Load address of window
  1821.         MOV     DH,[DI+BX+2]            ;  into source registers.
  1822.                CALL    EMS_MOVE_DATA
  1823. ;Load in page from extended memory.
  1824. LOAD_PAGE:     POP    DX            ;Pop new page address
  1825.         POP    AX
  1826.         MOV    DH,1            ;Search for primary page.
  1827.         CALL    EMS_CHK_LOCAL        ;See if page mapped elsewhere
  1828.         MOV    CX,BX                   ;Copy page array index
  1829.         INC    CX               ;Make non-zero number
  1830.         MOV    MOVE_BUSY_FLAG,CL    ;Busy = page being loaded
  1831.         MOV    DH,1            ;Set primary flag
  1832.          MOV     [SI+BX+2],DX            ;Load new address into the
  1833.         MOV     [SI+BX],AX        ;  page map array.
  1834.           MOV    SAVED_ADDR_LOW,AX    ;Save address of page to be
  1835.         MOV    SAVED_ADDR_HIGH,DL    ;  loaded.
  1836.         JC    EMS_EXCH_EXIT           ;If map local, exit
  1837.                 MOV    CX,[DI+BX]             ;Load window address
  1838.         MOV    DH,[DI+BX+2]
  1839.         XCHG    AX,CX            ;Put source and destination
  1840.         XCHG    DL,DH            ;  addresses in proper place.
  1841.                 CALL    EMS_MOVE_DATA        ;Move memory
  1842. EMS_EXCH_EXIT:    MOV    MOVE_BUSY_FLAG,0     ;Clear move busy flag
  1843.                   POP     CX                      ;Restore GDT data
  1844.           MOV    SOURCE.BASE_ADRH,CL
  1845.           MOV    DEST.BASE_ADRH,CH
  1846.          POP     SOURCE.BASE_ADRL
  1847.                   POP     DEST.BASE_ADRL
  1848.         POP    ES            ;Restore registers
  1849.         POP    DS
  1850.         POP    SI
  1851.         POP    CX
  1852.         RET
  1853. EMS_EXCH_PAG     ENDP
  1854. ;-----------------------------------------------------------------------------
  1855. ;EMS CHK LOCAL compares address to addresses in map array.
  1856. ;  Entry:  DL,AX - address
  1857. ;          BX - Index into map array
  1858. ;-----------------------------------------------------------------------------
  1859. EMS_CHK_LOCAL    PROC    NEAR
  1860.         PUSH    AX
  1861.         PUSH    BX
  1862.         PUSH    DX
  1863.         PUSH    DI
  1864.         OR    AX,AX            ;If the current page is
  1865.         JNE    EMS_CHK_LOC0        ;  unowned, don't do anything
  1866.         OR    DL,DL                   ;  but set the local flag and
  1867.         JE    EMS_CHK_LOC5        ;  exit.
  1868. EMS_CHK_LOC0:    MOV    DI,BX            ;Copy page index
  1869.         XOR    BX,BX                   ;Search the mapping table
  1870.         MOV    CX,4                    ;  for the address to be
  1871. EMS_CHK_LOC1:    CMP    AX,[SI+BX]              ;  mapped. If found, use
  1872.         JNE    EMS_CHK_LOC2            ;  the data from the mapped
  1873.         CMP    DX,[SI+BX+2]            ;  page since it may be more
  1874.         JE     EMS_CHK_LOC3            ;  accurate than the page
  1875. EMS_CHK_LOC2:    ADD    BX,4            ;  in extended memory.
  1876.         LOOP    EMS_CHK_LOC1
  1877.         JMP    SHORT EMS_CHK_LOC6    ;Local page not found
  1878. ;Local page found. If not the same page, copy data from primary to secondary.
  1879. EMS_CHK_LOC3:      CMP    DI,BX            ;Check for same page found
  1880.         JE    EMS_CHK_LOC5        ;Same page, do nothing
  1881.         OR    DH,DH            ;See if found primary
  1882.         JE    EMS_CHK_LOC4
  1883.         XCHG    DI,BX
  1884. EMS_CHK_LOC4:    MOV    BYTE PTR [SI+BX+3],1    ;Set primary flag
  1885.         XCHG    DI,BX
  1886.         MOV    BYTE PTR [SI+BX+3],0    ;Reset primary flag
  1887.         MOV    CL,12              ;Convert indices to offsets
  1888.         SAL    BX,CL            ;  within page frame.
  1889.         SAL    DI,CL
  1890.         PUSH    SI            ;Save map array pointer
  1891.         MOV    SI,BX            ;Put source offset into SI
  1892.         PUSH    DS
  1893.         MOV     AX,WINDOW_SEG
  1894.         MOV    DS,AX            ;Set the segments to the
  1895.         MOV    ES,AX            ;  page frame.
  1896.         MOV    CX,8192            ;8192 words or 16384 bytes
  1897.         CLD                ;Set direction
  1898.         REP    MOVSW            ;Move it
  1899.         POP    DS
  1900.         POP    SI
  1901. EMS_CHK_LOC5:    STC                ;Indicate local page found
  1902. EMS_CHK_LOC_EXIT:
  1903.         POP    DI
  1904.         POP    DX
  1905.         POP    BX
  1906.         POP    AX
  1907.         RET
  1908. EMS_CHK_LOC6:    CLC                ;Indicate local page not fnd
  1909.         JMP    SHORT EMS_CHK_LOC_EXIT
  1910. EMS_CHK_LOCAL    ENDP
  1911. ;-----------------------------------------------------------------------------
  1912. ;EMS MOVE DATA moves blocks of data using BIOS move block function.
  1913. ;  Entry:  DL,AX - destination address  CX,DH - source address.
  1914. ;-----------------------------------------------------------------------------
  1915. EMS_MOVE_DATA    PROC    NEAR
  1916.         PUSH    CX
  1917.         PUSH    SI
  1918.         MOV    SI,CS
  1919.         MOV    ES,SI
  1920.         MOV    SI,OFFSET GDT        ;ES:SI point to GDT
  1921.         MOV    DEST.BASE_ADRL,AX    ;store source address
  1922.         MOV    DEST.BASE_ADRH,DL
  1923.         MOV    SOURCE.BASE_ADRL,CX    ;store destination address
  1924.         MOV    SOURCE.BASE_ADRH,DH
  1925.         MOV    AH,87H            ;BIOS move extended block
  1926.         MOV    CX,2000H        ;move 8192 words
  1927.          INT    15H            ;call BIOS
  1928.         POP    SI
  1929.         POP    CX
  1930.         RET
  1931. EMS_MOVE_DATA    ENDP
  1932. ;-----------------------------------------------------------------------------
  1933. ;Init1. code initializes memory below this address then returns.
  1934. ;-----------------------------------------------------------------------------
  1935. INITIALIZE1    PROC    NEAR
  1936. INIT1:        ASSUME    CS:CODE,DS:CODE,ES:CODE
  1937.         MOV    DI,PAG_OWNER_TBL
  1938.         MOV    AX,TOTAL_PAGES      ;Compute size of page owner
  1939.         MOV    DX,3                    ;  table.
  1940.         MUL    DX
  1941.         MOV    CX,AX
  1942.         XOR    AX,AX                   ;load ff's into page owner tbl
  1943.         DEC    AX                      ;  because ff is invalid hndl.
  1944.         REP    STOSB
  1945.         MOV    AX,TOTAL_HANDLES    ;Compute size of handle array
  1946.         MOV    AH,9            ;9 bytes / handle
  1947.         MUL    AH
  1948.         MOV    CX,AX
  1949.         XOR    AX,AX
  1950.         REP    STOSW
  1951.         MOV    DI,HANDLE_ARRAY        ;activate system handle
  1952.         DEC    BYTE PTR [DI]
  1953.         MOV    DI,MAP_ARRAY_PTR
  1954.         MOV    CX,INT_SAVE_SIZE    ;Get number of save areas
  1955.         INC    CX            ;Add 1 for active map
  1956. EMS_INIT_L2:
  1957.         MOV    WORD PTR [DI],0FFFFH    ;Mark space as free
  1958.         INC    DI            ;Move pointer past free flag
  1959.         INC    DI
  1960.         PUSH    CX
  1961.         MOV    CX,8            ;Clear save area
  1962.         REP    STOSW
  1963.         POP    CX
  1964.         LOOP    EMS_INIT_L2
  1965.         RET
  1966. INITIALIZE1    ENDP
  1967. ;======================  End of resident Code  =============================
  1968. DATA_START    =    $
  1969. VDISK_HEADER     DB    'VDISK  V'
  1970. ERRMSG        DB    'Not enough memory',13,10,'$'
  1971. ;===========================================================================
  1972. ;Initialize. This routine sets up the EMS driver.
  1973. ;===========================================================================
  1974. INITIALIZE    PROC    NEAR
  1975.         ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  1976.         PUSH    CS            ;Parse command line
  1977.         POP    ES
  1978.         LDS    SI,[REQ_HEADADR]    ;get back addr of hdr
  1979.         ASSUME    DS:NOTHING,ES:CODE
  1980.         LDS    SI,DS:[SI.CONFIG_PTR]   ;Get pointer to config line
  1981.         MOV    BH,1            ;Look for first non-character
  1982.         MOV    CX,80            ;80 characters in line
  1983.         CALL    SCAN_FOR                ;Scan for non-character.
  1984.          OR    AH,AH            ;see if found
  1985.         JNE    CHK_FOR_VDISK        ;not found, skip remainder
  1986.         XOR    BH,BH            ;Look for next character
  1987.         CALL    SCAN_FOR        ;Scan for character
  1988.          OR    AH,AH            ;see if found
  1989.         JNE    CHK_FOR_VDISK        ;not found, skip remainder
  1990. ;-----------------------------------------------------------------------------
  1991. ;Non-blank line after driver name. Attempt to convert to memory size in Kbytes
  1992. ;-----------------------------------------------------------------------------
  1993.         DEC    SI            ;backup to 1st number
  1994.         MOV    CX,5            ;Max 5 numbers.
  1995.         XOR    AX,AX            ;Clear running total
  1996.         MOV    DI,10            ;Decimal conversion constant
  1997. INIT_LOOP1:     MOV     BL,DS:[SI]        ;Get number
  1998.         INC    SI            ;Point to next number.
  1999.         SUB    BL,'0'                  ;Convert to number and see
  2000.         JB      INIT_SKIP1              ;  if in range for a number.
  2001.         CMP    BL,9
  2002.         JA      INIT_SKIP1
  2003.         XOR    BH,BH
  2004.         MUL    DI              ;Mul by 16 to convert to hex
  2005.         ADD    AX,BX            ;add to current total
  2006.         LOOP    INIT_LOOP1
  2007. ;-----------------------------------------------------------------------------
  2008. ;Compute number of pages available for allocated memory.
  2009. ;-----------------------------------------------------------------------------
  2010. INIT_SKIP1:    XOR    DX,DX            ;Clear high word for divide
  2011.         MOV    DI,16                   ;Divide number of Kbytes
  2012.         DIV    DI                      ;  by 16 Kbytes / page.
  2013.         OR    AX,AX            ;if number less than 1 page
  2014.         JE     CHK_FOR_VDISK        ;  use default 24 pages.
  2015.         MOV    CS:TOTAL_PAGES,AX    ;Save number of pages.
  2016. ;-----------------------------------------------------------------------------
  2017. ;Check for vdisk driver by reading int 19 vector.
  2018. ;-----------------------------------------------------------------------------
  2019. CHK_FOR_VDISK:    PUSH    CS            ;Set DS = CS
  2020.         POP    DS
  2021.         ASSUME     DS:CODE
  2022.         MOV    AX,3519H        ;Get interrupt vector 19
  2023.         INT    21H            ;ES points to VDISK segment
  2024.         MOV    DI,12H            ;VDISK header at offset 12h
  2025.         MOV    SI,OFFSET VDISK_HEADER
  2026.         MOV    CX,8            ;8 characters in header
  2027.         XOR    BX,BX            ;assume no memory used by vdisk
  2028.         REPE    CMPSB            ;Compare header
  2029.         JNE     CHK_EXT_MEM
  2030. ;-----------------------------------------------------------------------------
  2031. ;If VDISK present, read top of available memory from inside VDISK driver.
  2032. ;-----------------------------------------------------------------------------
  2033.         MOV    SI,2CH            ;load offset of memory used
  2034.         MOV    AX,ES:[SI]        ;Get amount of memory used by
  2035.         MOV    DL,ES:[SI+2]        ;  vdisk
  2036.         SUB    DL,10H            ;Subtract 1 Mbyte starting adr
  2037.         XOR    DH,DH
  2038.         MOV    BX,16384        ;Convert to 16k pages
  2039.         DIV    BX
  2040.         MOV    BX,AX            ;save result in BX
  2041. ;-----------------------------------------------------------------------------
  2042. ;Find upper limit of extended memory.
  2043. ;-----------------------------------------------------------------------------
  2044. CHK_EXT_MEM:    PUSH    CS            ;ES = CS
  2045.         POP    ES
  2046.         ASSUME    ES:CODE
  2047.         MOV    AH,88H            ;Get extended memory function
  2048.         CLC                ;clr err flag. (fix IBMCACHE)
  2049.         INT    15H            ;Returns extended memory in
  2050.         JC     EXTEND_ERROR         ;  1k pages.
  2051.         MOV    CL,4            ;Convert number of 1k pages
  2052.         SAR    AX,CL            ;  into number of 16k pages.
  2053.         SUB    AX,TOTAL_PAGES        ;See if there is enough room.
  2054.         JL    EXTEND_ERROR
  2055.         CMP    AX,BX            ;Subtract memory used by vdisk
  2056.         JGE    EXTEND_MEM_OK1
  2057. EXTEND_ERROR:    JMP    DISP_ERR        ;Error, abort instalation.
  2058. ;-----------------------------------------------------------------------------
  2059. ;Compute the starting address of the extended memory area for int 15.
  2060. ;-----------------------------------------------------------------------------
  2061. EXTEND_MEM_OK1:    PUSH    CS                      ;  ES = CS
  2062.         POP    ES                      ;Convert memory req. to 1k
  2063.         ASSUME    ES:CODE                 ;  pages then store this
  2064.         MOV    CL,4                    ;  value for use as the new
  2065.         SAL    AX,CL                   ;  extended memory limit.
  2066.         MOV    EXT_MEM_LIMIT,AX
  2067.         MOV    CX,1024            ;Convert number of 1024
  2068.                 MUL    CX                      ;  byte pages to absolute adr
  2069.         ADD    DL,10H                  ;Add starting address of
  2070.         MOV    EXTEND_ADRL,AX          ;  extended memory and
  2071.         MOV    EXTEND_ADRH,DL          ;  save.
  2072. ;-----------------------------------------------------------------------------
  2073. ;Initialize the variables and pointers needed to emulate the EMS spec.
  2074. ;-----------------------------------------------------------------------------
  2075.         MOV    CX,OFFSET DATA_START    ;Get end of installed code.
  2076.         MOV    PAG_OWNER_TBL,CX    ;Save pointer to page table
  2077.         MOV    AX,TOTAL_PAGES          ;Get number of pages
  2078.         MOV    AH,3            ;Compute the size of the
  2079.         MUL    AH                      ;  page frame.
  2080.         ADD    CX,AX               ;Add to current pointer
  2081.         MOV    HANDLE_ARRAY,CX         ;Save pointer to handle array
  2082.         MOV    AX,TOTAL_HANDLES    ;compute size of handle
  2083.         MOV    AH,9                    ;  array using 9 bytes / hdl.
  2084.         MUL    AH
  2085.         ADD    CX,AX
  2086.         MOV    MAP_ARRAY_PTR,CX    ;map array 18 bytes. 4 arrays.
  2087.         MOV    AX,INT_SAVE_SIZE    ;Get number of save areas
  2088.         INC    AX            ;Add 1 for active map
  2089.         MOV    AH,18            ;Compute size of internal
  2090.         MUL    AH                      ;  save array using 18 bytes
  2091.         ADD    AX,CX                   ;  per save area
  2092. ;-----------------------------------------------------------------------------
  2093. ;Compute the segment address of the page frame
  2094. ;-----------------------------------------------------------------------------
  2095.         ADD    AX,15            ;Add 15 to round to next seg
  2096.          MOV    CL,4            ;convert offset into a
  2097.          SHR    AX,CL            ;segment value
  2098.         MOV    BX,CS            ;get code segment
  2099.         ADD    AX,BX            ;add code seg to current ptr
  2100.         MOV    WINDOW_SEG,AX        ;store starting segment of ems
  2101.         PUSH    AX            ;  page frame.
  2102. ;-----------------------------------------------------------------------------
  2103. ;Generate and store abolute addresses of window pages.
  2104. ;-----------------------------------------------------------------------------
  2105.         MOV    DX,16            ;Convert segment into
  2106.         MUL    DX                      ;  absolute address.
  2107.         MOV    DI,OFFSET WINDOW_ADDR_BASE
  2108.         MOV    CX,4
  2109. EMS_INIT_L3:    MOV    [DI],AX            ;Save absolute address
  2110.         MOV    [DI+2],DX
  2111.         ADD    AX,16384                ;point to next page address
  2112.         ADC    DX,0
  2113.         ADD    DI,4                 ;point to next save address
  2114.         LOOP    EMS_INIT_L3
  2115. ;-----------------------------------------------------------------------------
  2116. ;Write the memory requirments to the device driver header
  2117. ;-----------------------------------------------------------------------------
  2118.         POP    BX                    ;Get back seg start of window
  2119.         ADD    BX,1000H                ;Add 64 Kbytes.
  2120.         XOR    AX,AX            ;Start at offset 0
  2121.         PUSH    ES
  2122.         CALL    LOAD_HEADER          ;Load memory requirments into
  2123.         POP    ES                      ;  request header.
  2124.         MOV    DX,OFFSET PROGRAM    ;Print copyright
  2125.         MOV    AH,9
  2126.         INT    21H
  2127. ;-----------------------------------------------------------------------------
  2128. ;Vector interrupt 15h to reserve the extended memory.
  2129. ;-----------------------------------------------------------------------------
  2130.         PUSH    ES
  2131.         MOV    AX,3515H        ;Get interrupt vector 15
  2132.         INT    21H
  2133.         MOV    OLD_INT15HO,BX        ;save vector
  2134.         MOV    OLD_INT15HS,ES
  2135.         POP    ES
  2136.         MOV    AX,2515H        ;Set interrupt vector 15
  2137.         MOV    DX,OFFSET INT_15H
  2138.         INT    21H            ;Call DOS
  2139. ;-----------------------------------------------------------------------------
  2140. ;Vector the 67h interrupt to the driver. Jump to final installation code.
  2141. ;-----------------------------------------------------------------------------
  2142.         MOV    AX,2567H        ;Set interrupt vector 67
  2143.         MOV    DX,OFFSET INT_67H
  2144.         INT    21H            ;Call DOS
  2145.         JMP    INIT1            ;jump to final init. code.
  2146. ;-----------------------------------------------------------------------------
  2147. ;error routine to abort instalation.
  2148. ;-----------------------------------------------------------------------------
  2149. DISP_ERR:    MOV    DX,OFFSET ERRMSG    ;Tell user that the driver is
  2150.         MOV    AH,9            ;  not loaded.
  2151.         INT    21H
  2152.         MOV    AX,3000H        ;Get DOS version
  2153.         INT    21H
  2154.         XCHG    AL,AH            ;Put number in proper order
  2155.         CMP    AX,31EH            ;See if DOS 3.3
  2156.         MOV    AX,OFFSET DRIVER_END    ;Offset of device driver code
  2157.         MOV    BX,CS               ;If >3.3, abort install with
  2158.         JB     ERROR_ABORT_SKIP    ; 0 memory. Otherwise leave
  2159.         XOR    AX,AX            ;  driver stub installed.
  2160. ERROR_ABORT_SKIP:
  2161.         CALL    LOAD_HEADER        ;Load into request header
  2162.         MOV    AX,8002             ;Indicate error in the
  2163.         RET                ;  driver return code.
  2164. ;-----------------------------------------------------------------------------
  2165. ;LOADHEADER loads the amount of memory needed into the request header.
  2166. ;-----------------------------------------------------------------------------
  2167. LOAD_HEADER    PROC    NEAR
  2168.         LES    DI,[REQ_HEADADR]        ;get addr of req hdr
  2169.         MOV    WORD PTR ES:[DI.ADDRESS],AX    ;Store offset and
  2170.         MOV    WORD PTR ES:[DI.ADDRESS+2],BX   ;  code segment.
  2171.         RET
  2172. LOAD_HEADER    ENDP
  2173. ;-----------------------------------------------------------------------------
  2174. ;ScanFor - scans for first (non)occurance of character in line.
  2175. ; Entry -  BH - 0 = scan for non character, 1 = scan for character.
  2176. ;          DS:SI - string to scan.   CX - length of string
  2177. ; Exit  -  AH - 1 = end of line found.
  2178. ;-----------------------------------------------------------------------------
  2179. SCAN_FOR    PROC    NEAR
  2180.         XOR    AH,AH               ;Clear found flag
  2181. SCAN_LOOP1:    LODSB                ;Get character
  2182.         OR    BH,BH            ;see if first match or
  2183.         JE    SCAN_SKIP1        ;  mismatch. 0 = match
  2184.         CMP    AL,20H                  ;Check for noncharacter.
  2185.         JLE    SCAN_SKIP4
  2186.         JMP    SHORT SCAN_SKIP2
  2187. SCAN_SKIP1:    CMP    AL,20H            ;Check for character
  2188.         JG     SCAN_SKIP4
  2189. SCAN_SKIP2:    CMP    AL,13            ;Check for CR
  2190.         JE    SCAN_SKIP3
  2191.         CMP    AL,10            ;Check for LF
  2192.         JE    SCAN_SKIP3
  2193.         LOOP    SCAN_LOOP1
  2194. SCAN_SKIP3:    INC    AH            ;character not found
  2195. SCAN_SKIP4:    RET
  2196. SCAN_FOR    ENDP
  2197. END_OF_CODE    =    $
  2198. INITIALIZE    ENDP
  2199. CODE        ENDS
  2200.         END
  2201.